aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs119
-rw-r--r--OpenSim/Client/MXP/ClientStack/MXPClientView.cs19
-rw-r--r--OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs8
-rw-r--r--OpenSim/Data/AssetDataBase.cs2
-rw-r--r--OpenSim/Data/IAssetData.cs2
-rw-r--r--OpenSim/Data/IUserAccountData.cs1
-rw-r--r--OpenSim/Data/MSSQL/MSSQLAssetData.cs4
-rw-r--r--OpenSim/Data/MSSQL/MSSQLUserAccountData.cs5
-rw-r--r--OpenSim/Data/MySQL/MySQLAssetData.cs4
-rw-r--r--OpenSim/Data/MySQL/MySQLUserAccountData.cs15
-rw-r--r--OpenSim/Data/MySQL/Resources/RegionStore.migrations2
-rw-r--r--OpenSim/Data/Null/NullUserAccountData.cs5
-rw-r--r--OpenSim/Data/SQLite/SQLiteAssetData.cs4
-rw-r--r--OpenSim/Data/SQLite/SQLiteUserAccountData.cs5
-rw-r--r--OpenSim/Data/SQLiteLegacy/SQLiteAssetData.cs4
-rw-r--r--OpenSim/Data/SQLiteLegacy/SQLiteUserAccountData.cs5
-rw-r--r--OpenSim/Framework/AssetBase.cs8
-rw-r--r--OpenSim/Framework/AvatarAppearance.cs109
-rw-r--r--OpenSim/Framework/Communications/RestClient.cs2
-rw-r--r--OpenSim/Framework/ICallingCardModule.cs13
-rw-r--r--OpenSim/Framework/IClientAPI.cs11
-rw-r--r--OpenSim/Framework/LandData.cs2
-rw-r--r--OpenSim/Framework/ParcelMediaCommandEnum.cs2
-rw-r--r--OpenSim/Framework/PluginLoader.cs17
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs2
-rw-r--r--OpenSim/Framework/RegionInfo.cs1
-rw-r--r--OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs65
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs19
-rw-r--r--OpenSim/Framework/Servers/VersionInfo.cs4
-rw-r--r--OpenSim/Framework/TaskInventoryDictionary.cs162
-rw-r--r--OpenSim/Framework/TaskInventoryItem.cs5
-rw-r--r--OpenSim/Framework/UndoStack.cs58
-rw-r--r--OpenSim/Framework/Util.cs26
-rw-r--r--OpenSim/Framework/Watchdog.cs8
-rw-r--r--OpenSim/Region/Application/OpenSim.cs2
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs82
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs695
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs10
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs66
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs16
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs127
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs11
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs62
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs115
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs17
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs26
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs38
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs62
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs63
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs57
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs770
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs74
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs17
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs15
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs18
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs39
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs351
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs37
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs35
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs4
-rw-r--r--OpenSim/Region/Examples/SimpleModule/ComplexObject.cs5
-rw-r--r--OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs20
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityInventory.cs3
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IInterregionComms.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISnmpModule.cs27
-rw-r--r--OpenSim/Region/Framework/ModuleLoader.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs226
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs34
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs249
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs324
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs230
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs664
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs296
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs713
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs979
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneViewer.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs168
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs8
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs4
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs3
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs16
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs9
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs4
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs3
-rw-r--r--OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs1437
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs3861
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs375
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs (renamed from OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs)46
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs3846
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs122
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs98
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs1
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs6
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPrim.cs2
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs82
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs20
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs1884
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs53
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs16
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs32
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs7
-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/Instance/ScriptInstance.cs47
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs30
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs341
-rw-r--r--OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs1
-rw-r--r--OpenSim/Server/Handlers/Simulation/AgentHandlers.cs23
-rw-r--r--OpenSim/Services/AssetService/AssetService.cs5
-rw-r--r--OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs8
-rw-r--r--OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs62
-rw-r--r--OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs5
-rw-r--r--OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs120
-rw-r--r--OpenSim/Services/Connectors/Land/LandServiceConnector.cs2
-rw-r--r--OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs11
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs4
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs5
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs14
-rw-r--r--OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs5
-rw-r--r--OpenSim/Services/HypergridService/UserAccountCache.cs5
-rw-r--r--OpenSim/Services/Interfaces/IAttachmentsService.cs17
-rw-r--r--OpenSim/Services/Interfaces/IGridService.cs14
-rw-r--r--OpenSim/Services/Interfaces/ISimulationService.cs8
-rw-r--r--OpenSim/Services/Interfaces/IUserAccountService.cs1
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginResponse.cs6
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs9
-rw-r--r--OpenSim/Services/UserAccountService/UserAccountService.cs15
-rw-r--r--OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs3
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs8
155 files changed, 17301 insertions, 3132 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index 1b4d1ea..9659883 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -128,6 +128,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
128 availableMethods["admin_region_query"] = XmlRpcRegionQueryMethod; 128 availableMethods["admin_region_query"] = XmlRpcRegionQueryMethod;
129 availableMethods["admin_shutdown"] = XmlRpcShutdownMethod; 129 availableMethods["admin_shutdown"] = XmlRpcShutdownMethod;
130 availableMethods["admin_broadcast"] = XmlRpcAlertMethod; 130 availableMethods["admin_broadcast"] = XmlRpcAlertMethod;
131 availableMethods["admin_dialog"] = XmlRpcDialogMethod;
131 availableMethods["admin_restart"] = XmlRpcRestartMethod; 132 availableMethods["admin_restart"] = XmlRpcRestartMethod;
132 availableMethods["admin_load_heightmap"] = XmlRpcLoadHeightmapMethod; 133 availableMethods["admin_load_heightmap"] = XmlRpcLoadHeightmapMethod;
133 // User management 134 // User management
@@ -215,18 +216,53 @@ namespace OpenSim.ApplicationPlugins.RemoteController
215 if (!m_application.SceneManager.TryGetScene(regionID, out rebootedScene)) 216 if (!m_application.SceneManager.TryGetScene(regionID, out rebootedScene))
216 throw new Exception("region not found"); 217 throw new Exception("region not found");
217 218
219 string message;
220 List<int> times = new List<int>();
221
222 if (requestData.ContainsKey("alerts"))
223 {
224 string[] alertTimes = requestData["alerts"].ToString().Split( new char[] {','});
225 foreach (string a in alertTimes)
226 times.Add(Convert.ToInt32(a));
227 }
228 else
229 {
230 int timeout = 30;
231 if (requestData.ContainsKey("milliseconds"))
232 timeout = Int32.Parse(requestData["milliseconds"].ToString()) / 1000;
233 while (timeout > 0)
234 {
235 times.Add(timeout);
236 if (timeout > 300)
237 timeout -= 120;
238 else if (timeout > 30)
239 timeout -= 30;
240 else
241 timeout -= 15;
242 }
243 }
244
245 message = "Region is restarting in {0}. Please save what you are doing and log out.";
246
247 if (requestData.ContainsKey("message"))
248 message = requestData["message"].ToString();
249
250 bool notice = true;
251 if (requestData.ContainsKey("noticetype")
252 && ((string)requestData["noticetype"] == "dialog"))
253 {
254 notice = false;
255 }
256
218 responseData["rebooting"] = true; 257 responseData["rebooting"] = true;
219 258
220 IRestartModule restartModule = rebootedScene.RequestModuleInterface<IRestartModule>(); 259 IRestartModule restartModule = rebootedScene.RequestModuleInterface<IRestartModule>();
221 if (restartModule != null) 260 if (restartModule != null)
222 { 261 {
223 List<int> times = new List<int> { 30, 15 }; 262 restartModule.ScheduleRestart(UUID.Zero, message, times.ToArray(), notice);
224
225 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true);
226 responseData["success"] = true; 263 responseData["success"] = true;
227 } 264 }
228 response.Value = responseData; 265 response.Value = responseData;
229
230 } 266 }
231 catch (Exception e) 267 catch (Exception e)
232 { 268 {
@@ -289,6 +325,53 @@ namespace OpenSim.ApplicationPlugins.RemoteController
289 m_log.Info("[RADMIN]: Alert request complete"); 325 m_log.Info("[RADMIN]: Alert request complete");
290 return response; 326 return response;
291 } 327 }
328 public XmlRpcResponse XmlRpcDialogMethod(XmlRpcRequest request, IPEndPoint remoteClient)
329 {
330 XmlRpcResponse response = new XmlRpcResponse();
331 Hashtable responseData = new Hashtable();
332
333 m_log.Info("[RADMIN]: Dialog request started");
334
335 try
336 {
337 Hashtable requestData = (Hashtable)request.Params[0];
338
339 CheckStringParameters(request, new string[] { "password", "from", "message" });
340
341 if (m_requiredPassword != String.Empty &&
342 (!requestData.Contains("password") || (string)requestData["password"] != m_requiredPassword))
343 throw new Exception("wrong password");
344
345 string message = (string)requestData["message"];
346 string fromuuid = (string)requestData["from"];
347 m_log.InfoFormat("[RADMIN]: Broadcasting: {0}", message);
348
349 responseData["accepted"] = true;
350 responseData["success"] = true;
351 response.Value = responseData;
352
353 m_application.SceneManager.ForEachScene(
354 delegate(Scene scene)
355 {
356 IDialogModule dialogModule = scene.RequestModuleInterface<IDialogModule>();
357 if (dialogModule != null)
358 dialogModule.SendNotificationToUsersInRegion(UUID.Zero, fromuuid, message);
359 });
360 }
361 catch (Exception e)
362 {
363 m_log.ErrorFormat("[RADMIN]: Broadcasting: failed: {0}", e.Message);
364 m_log.DebugFormat("[RADMIN]: Broadcasting: failed: {0}", e.ToString());
365
366 responseData["accepted"] = false;
367 responseData["success"] = false;
368 responseData["error"] = e.Message;
369 response.Value = responseData;
370 }
371
372 m_log.Info("[RADMIN]: Alert request complete");
373 return response;
374 }
292 375
293 public XmlRpcResponse XmlRpcLoadHeightmapMethod(XmlRpcRequest request, IPEndPoint remoteClient) 376 public XmlRpcResponse XmlRpcLoadHeightmapMethod(XmlRpcRequest request, IPEndPoint remoteClient)
294 { 377 {
@@ -396,13 +479,33 @@ namespace OpenSim.ApplicationPlugins.RemoteController
396 message = "Region is going down now."; 479 message = "Region is going down now.";
397 } 480 }
398 481
399 m_application.SceneManager.ForEachScene( 482 if (requestData.ContainsKey("noticetype")
483 && ((string) requestData["noticetype"] == "dialog"))
484 {
485 m_application.SceneManager.ForEachScene(
400 delegate(Scene scene) 486 delegate(Scene scene)
401 { 487 {
402 IDialogModule dialogModule = scene.RequestModuleInterface<IDialogModule>(); 488 IDialogModule dialogModule = scene.RequestModuleInterface<IDialogModule>();
403 if (dialogModule != null) 489 if (dialogModule != null)
490 dialogModule.SendNotificationToUsersInRegion(UUID.Zero, "System", message);
491 });
492 }
493 else
494 {
495 if (!requestData.ContainsKey("noticetype")
496 || ((string)requestData["noticetype"] != "none"))
497 {
498 m_application.SceneManager.ForEachScene(
499 delegate(Scene scene)
500 {
501 IDialogModule dialogModule = scene.RequestModuleInterface<IDialogModule>();
502 if (dialogModule != null)
404 dialogModule.SendGeneralAlert(message); 503 dialogModule.SendGeneralAlert(message);
405 }); 504 });
505 }
506 }
507
508
406 509
407 // Perform shutdown 510 // Perform shutdown
408 System.Timers.Timer shutdownTimer = new System.Timers.Timer(timeout); // Wait before firing 511 System.Timers.Timer shutdownTimer = new System.Timers.Timer(timeout); // Wait before firing
@@ -2529,8 +2632,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController
2529 else throw new Exception("neither region_name nor region_uuid given"); 2632 else throw new Exception("neither region_name nor region_uuid given");
2530 2633
2531 Scene scene = m_application.SceneManager.CurrentScene; 2634 Scene scene = m_application.SceneManager.CurrentScene;
2532 int health = scene.GetHealth(); 2635 int flags;
2636 string text;
2637 int health = scene.GetHealth(out flags, out text);
2533 responseData["health"] = health; 2638 responseData["health"] = health;
2639 responseData["flags"] = flags;
2640 responseData["message"] = text;
2534 2641
2535 response.Value = responseData; 2642 response.Value = responseData;
2536 } 2643 }
diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
index 1d93382..302f7ae 100644
--- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
+++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
@@ -593,6 +593,7 @@ namespace OpenSim.Client.MXP.ClientStack
593 public event DisconnectUser OnDisconnectUser; 593 public event DisconnectUser OnDisconnectUser;
594 public event RequestAvatarProperties OnRequestAvatarProperties; 594 public event RequestAvatarProperties OnRequestAvatarProperties;
595 public event SetAlwaysRun OnSetAlwaysRun; 595 public event SetAlwaysRun OnSetAlwaysRun;
596 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
596 public event TeleportLandmarkRequest OnTeleportLandmarkRequest; 597 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
597 public event DeRezObject OnDeRezObject; 598 public event DeRezObject OnDeRezObject;
598 public event Action<IClientAPI> OnRegionHandShakeReply; 599 public event Action<IClientAPI> OnRegionHandShakeReply;
@@ -835,10 +836,18 @@ namespace OpenSim.Client.MXP.ClientStack
835 836
836 public void Close() 837 public void Close()
837 { 838 {
839 Close(true);
840 }
841
842 public void Close(bool sendStop)
843 {
838 m_log.Info("[MXP ClientStack] Close Called"); 844 m_log.Info("[MXP ClientStack] Close Called");
839 845
840 // Tell the client to go 846 // Tell the client to go
841 SendLogoutPacket(); 847 if (sendStop == true)
848 {
849 SendLogoutPacket();
850 }
842 851
843 // Let MXPPacketServer clean it up 852 // Let MXPPacketServer clean it up
844 if (Session.SessionState != SessionState.Disconnected) 853 if (Session.SessionState != SessionState.Disconnected)
@@ -884,7 +893,13 @@ namespace OpenSim.Client.MXP.ClientStack
884 // Need to translate to MXP somehow 893 // Need to translate to MXP somehow
885 } 894 }
886 895
887 public void SendKillObject(ulong regionHandle, uint localID) 896 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
897 {
898 foreach (uint localID in localIDs)
899 SendKillObject(regionHandle, localID);
900 }
901
902 private void SendKillObject(ulong regionHandle, uint localID)
888 { 903 {
889 DisappearanceEventMessage de = new DisappearanceEventMessage(); 904 DisappearanceEventMessage de = new DisappearanceEventMessage();
890 de.ObjectIndex = localID; 905 de.ObjectIndex = localID;
diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs
index f2b58d3..ba6456b 100644
--- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs
+++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs
@@ -290,6 +290,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
290 public event GenericCall2 OnStopMovement = delegate { }; 290 public event GenericCall2 OnStopMovement = delegate { };
291 public event Action<UUID> OnRemoveAvatar = delegate { }; 291 public event Action<UUID> OnRemoveAvatar = delegate { };
292 public event ObjectPermissions OnObjectPermissions = delegate { }; 292 public event ObjectPermissions OnObjectPermissions = delegate { };
293 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy = delegate { };
293 public event CreateNewInventoryItem OnCreateNewInventoryItem = delegate { }; 294 public event CreateNewInventoryItem OnCreateNewInventoryItem = delegate { };
294 public event LinkInventoryItem OnLinkInventoryItem = delegate { }; 295 public event LinkInventoryItem OnLinkInventoryItem = delegate { };
295 public event CreateInventoryFolder OnCreateNewInventoryFolder = delegate { }; 296 public event CreateInventoryFolder OnCreateNewInventoryFolder = delegate { };
@@ -452,6 +453,11 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
452 453
453 public void Close() 454 public void Close()
454 { 455 {
456 Close(true);
457 }
458
459 public void Close(bool sendStop)
460 {
455 throw new System.NotImplementedException(); 461 throw new System.NotImplementedException();
456 } 462 }
457 463
@@ -485,7 +491,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
485 throw new System.NotImplementedException(); 491 throw new System.NotImplementedException();
486 } 492 }
487 493
488 public void SendKillObject(ulong regionHandle, uint localID) 494 public void SendKillObject(ulong regionHandle, List<uint> localID)
489 { 495 {
490 throw new System.NotImplementedException(); 496 throw new System.NotImplementedException();
491 } 497 }
diff --git a/OpenSim/Data/AssetDataBase.cs b/OpenSim/Data/AssetDataBase.cs
index e1a810c..b4ae913 100644
--- a/OpenSim/Data/AssetDataBase.cs
+++ b/OpenSim/Data/AssetDataBase.cs
@@ -38,7 +38,7 @@ namespace OpenSim.Data
38 { 38 {
39 public abstract AssetBase GetAsset(UUID uuid); 39 public abstract AssetBase GetAsset(UUID uuid);
40 40
41 public abstract void StoreAsset(AssetBase asset); 41 public abstract bool StoreAsset(AssetBase asset);
42 public abstract bool ExistsAsset(UUID uuid); 42 public abstract bool ExistsAsset(UUID uuid);
43 43
44 public abstract List<AssetMetadata> FetchAssetMetadataSet(int start, int count); 44 public abstract List<AssetMetadata> FetchAssetMetadataSet(int start, int count);
diff --git a/OpenSim/Data/IAssetData.cs b/OpenSim/Data/IAssetData.cs
index f31b215c..0c8eadd 100644
--- a/OpenSim/Data/IAssetData.cs
+++ b/OpenSim/Data/IAssetData.cs
@@ -34,7 +34,7 @@ namespace OpenSim.Data
34 public interface IAssetDataPlugin : IPlugin 34 public interface IAssetDataPlugin : IPlugin
35 { 35 {
36 AssetBase GetAsset(UUID uuid); 36 AssetBase GetAsset(UUID uuid);
37 void StoreAsset(AssetBase asset); 37 bool StoreAsset(AssetBase asset);
38 bool ExistsAsset(UUID uuid); 38 bool ExistsAsset(UUID uuid);
39 List<AssetMetadata> FetchAssetMetadataSet(int start, int count); 39 List<AssetMetadata> FetchAssetMetadataSet(int start, int count);
40 void Initialise(string connect); 40 void Initialise(string connect);
diff --git a/OpenSim/Data/IUserAccountData.cs b/OpenSim/Data/IUserAccountData.cs
index 906ba6c..bc7eda7 100644
--- a/OpenSim/Data/IUserAccountData.cs
+++ b/OpenSim/Data/IUserAccountData.cs
@@ -50,5 +50,6 @@ namespace OpenSim.Data
50 bool Store(UserAccountData data); 50 bool Store(UserAccountData data);
51 bool Delete(string field, string val); 51 bool Delete(string field, string val);
52 UserAccountData[] GetUsers(UUID scopeID, string query); 52 UserAccountData[] GetUsers(UUID scopeID, string query);
53 UserAccountData[] GetUsersWhere(UUID scopeID, string where);
53 } 54 }
54} 55}
diff --git a/OpenSim/Data/MSSQL/MSSQLAssetData.cs b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
index c7488d8..c882555 100644
--- a/OpenSim/Data/MSSQL/MSSQLAssetData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLAssetData.cs
@@ -143,7 +143,7 @@ namespace OpenSim.Data.MSSQL
143 /// Create asset in m_database 143 /// Create asset in m_database
144 /// </summary> 144 /// </summary>
145 /// <param name="asset">the asset</param> 145 /// <param name="asset">the asset</param>
146 override public void StoreAsset(AssetBase asset) 146 override public bool StoreAsset(AssetBase asset)
147 { 147 {
148 148
149 string sql = 149 string sql =
@@ -192,10 +192,12 @@ namespace OpenSim.Data.MSSQL
192 try 192 try
193 { 193 {
194 command.ExecuteNonQuery(); 194 command.ExecuteNonQuery();
195 return true;
195 } 196 }
196 catch(Exception e) 197 catch(Exception e)
197 { 198 {
198 m_log.Error("[ASSET DB]: Error storing item :" + e.Message); 199 m_log.Error("[ASSET DB]: Error storing item :" + e.Message);
200 return false;
199 } 201 }
200 } 202 }
201 } 203 }
diff --git a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs
index e7c8dc5..f24b441 100644
--- a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs
@@ -238,5 +238,10 @@ namespace OpenSim.Data.MSSQL
238 return DoQuery(cmd); 238 return DoQuery(cmd);
239 } 239 }
240 } 240 }
241
242 public UserAccountData[] GetUsersWhere(UUID scopeID, string where)
243 {
244 return null;
245 }
241 } 246 }
242} 247}
diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs
index ed92f3e..0b0a638 100644
--- a/OpenSim/Data/MySQL/MySQLAssetData.cs
+++ b/OpenSim/Data/MySQL/MySQLAssetData.cs
@@ -153,7 +153,7 @@ namespace OpenSim.Data.MySQL
153 /// </summary> 153 /// </summary>
154 /// <param name="asset">Asset UUID to create</param> 154 /// <param name="asset">Asset UUID to create</param>
155 /// <remarks>On failure : Throw an exception and attempt to reconnect to database</remarks> 155 /// <remarks>On failure : Throw an exception and attempt to reconnect to database</remarks>
156 override public void StoreAsset(AssetBase asset) 156 override public bool StoreAsset(AssetBase asset)
157 { 157 {
158 lock (m_dbLock) 158 lock (m_dbLock)
159 { 159 {
@@ -201,12 +201,14 @@ namespace OpenSim.Data.MySQL
201 cmd.Parameters.AddWithValue("?data", asset.Data); 201 cmd.Parameters.AddWithValue("?data", asset.Data);
202 cmd.ExecuteNonQuery(); 202 cmd.ExecuteNonQuery();
203 cmd.Dispose(); 203 cmd.Dispose();
204 return true;
204 } 205 }
205 } 206 }
206 catch (Exception e) 207 catch (Exception e)
207 { 208 {
208 m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}", 209 m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}",
209 asset.FullID, asset.Name, e.Message); 210 asset.FullID, asset.Name, e.Message);
211 return false;
210 } 212 }
211 } 213 }
212 } 214 }
diff --git a/OpenSim/Data/MySQL/MySQLUserAccountData.cs b/OpenSim/Data/MySQL/MySQLUserAccountData.cs
index aa69d68..3b35222 100644
--- a/OpenSim/Data/MySQL/MySQLUserAccountData.cs
+++ b/OpenSim/Data/MySQL/MySQLUserAccountData.cs
@@ -80,5 +80,20 @@ namespace OpenSim.Data.MySQL
80 80
81 return DoQuery(cmd); 81 return DoQuery(cmd);
82 } 82 }
83
84 public UserAccountData[] GetUsersWhere(UUID scopeID, string where)
85 {
86 MySqlCommand cmd = new MySqlCommand();
87
88 if (scopeID != UUID.Zero)
89 {
90 where = "(ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (" + where + ")";
91 cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString());
92 }
93
94 cmd.CommandText = String.Format("select * from {0} where " + where, m_Realm);
95
96 return DoQuery(cmd);
97 }
83 } 98 }
84} 99}
diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
index ba8d538..645f4e8 100644
--- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
@@ -717,7 +717,7 @@ ALTER TABLE regionsettings ADD COLUMN loaded_creation_datetime int unsigned NOT
717 717
718COMMIT; 718COMMIT;
719 719
720:VERSION 32 720:VERSION 32 #---------------------
721 721
722BEGIN; 722BEGIN;
723CREATE TABLE `regionwindlight` ( 723CREATE TABLE `regionwindlight` (
diff --git a/OpenSim/Data/Null/NullUserAccountData.cs b/OpenSim/Data/Null/NullUserAccountData.cs
index ede23fb..772d821 100644
--- a/OpenSim/Data/Null/NullUserAccountData.cs
+++ b/OpenSim/Data/Null/NullUserAccountData.cs
@@ -156,5 +156,10 @@ namespace OpenSim.Data.Null
156 156
157 return false; 157 return false;
158 } 158 }
159
160 public UserAccountData[] GetUsersWhere(UUID scopeID, string where)
161 {
162 return null;
163 }
159 } 164 }
160} 165}
diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs
index 5b71897..9a4eb76 100644
--- a/OpenSim/Data/SQLite/SQLiteAssetData.cs
+++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs
@@ -124,7 +124,7 @@ namespace OpenSim.Data.SQLite
124 /// Create an asset 124 /// Create an asset
125 /// </summary> 125 /// </summary>
126 /// <param name="asset">Asset Base</param> 126 /// <param name="asset">Asset Base</param>
127 override public void StoreAsset(AssetBase asset) 127 override public bool StoreAsset(AssetBase asset)
128 { 128 {
129 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); 129 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString());
130 if (ExistsAsset(asset.FullID)) 130 if (ExistsAsset(asset.FullID))
@@ -146,6 +146,7 @@ namespace OpenSim.Data.SQLite
146 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data)); 146 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
147 147
148 cmd.ExecuteNonQuery(); 148 cmd.ExecuteNonQuery();
149 return true;
149 } 150 }
150 } 151 }
151 } 152 }
@@ -166,6 +167,7 @@ namespace OpenSim.Data.SQLite
166 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data)); 167 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
167 168
168 cmd.ExecuteNonQuery(); 169 cmd.ExecuteNonQuery();
170 return true;
169 } 171 }
170 } 172 }
171 } 173 }
diff --git a/OpenSim/Data/SQLite/SQLiteUserAccountData.cs b/OpenSim/Data/SQLite/SQLiteUserAccountData.cs
index 7a5de50..4d580c0 100644
--- a/OpenSim/Data/SQLite/SQLiteUserAccountData.cs
+++ b/OpenSim/Data/SQLite/SQLiteUserAccountData.cs
@@ -81,5 +81,10 @@ namespace OpenSim.Data.SQLite
81 81
82 return DoQuery(cmd); 82 return DoQuery(cmd);
83 } 83 }
84
85 public UserAccountData[] GetUsersWhere(UUID scopeID, string where)
86 {
87 return null;
88 }
84 } 89 }
85} 90}
diff --git a/OpenSim/Data/SQLiteLegacy/SQLiteAssetData.cs b/OpenSim/Data/SQLiteLegacy/SQLiteAssetData.cs
index df50902..3da298b 100644
--- a/OpenSim/Data/SQLiteLegacy/SQLiteAssetData.cs
+++ b/OpenSim/Data/SQLiteLegacy/SQLiteAssetData.cs
@@ -119,7 +119,7 @@ namespace OpenSim.Data.SQLiteLegacy
119 /// Create an asset 119 /// Create an asset
120 /// </summary> 120 /// </summary>
121 /// <param name="asset">Asset Base</param> 121 /// <param name="asset">Asset Base</param>
122 override public void StoreAsset(AssetBase asset) 122 override public bool StoreAsset(AssetBase asset)
123 { 123 {
124 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); 124 //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString());
125 if (ExistsAsset(asset.FullID)) 125 if (ExistsAsset(asset.FullID))
@@ -139,6 +139,7 @@ namespace OpenSim.Data.SQLiteLegacy
139 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data)); 139 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
140 140
141 cmd.ExecuteNonQuery(); 141 cmd.ExecuteNonQuery();
142 return true;
142 } 143 }
143 } 144 }
144 } 145 }
@@ -157,6 +158,7 @@ namespace OpenSim.Data.SQLiteLegacy
157 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data)); 158 cmd.Parameters.Add(new SqliteParameter(":Data", asset.Data));
158 159
159 cmd.ExecuteNonQuery(); 160 cmd.ExecuteNonQuery();
161 return true;
160 } 162 }
161 } 163 }
162 } 164 }
diff --git a/OpenSim/Data/SQLiteLegacy/SQLiteUserAccountData.cs b/OpenSim/Data/SQLiteLegacy/SQLiteUserAccountData.cs
index 27553c6..41a0177 100644
--- a/OpenSim/Data/SQLiteLegacy/SQLiteUserAccountData.cs
+++ b/OpenSim/Data/SQLiteLegacy/SQLiteUserAccountData.cs
@@ -77,5 +77,10 @@ namespace OpenSim.Data.SQLiteLegacy
77 77
78 return DoQuery(cmd); 78 return DoQuery(cmd);
79 } 79 }
80
81 public UserAccountData[] GetUsersWhere(UUID scopeID, string where)
82 {
83 return null;
84 }
80 } 85 }
81} 86}
diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs
index 53d28be..98fa846 100644
--- a/OpenSim/Framework/AssetBase.cs
+++ b/OpenSim/Framework/AssetBase.cs
@@ -60,6 +60,8 @@ namespace OpenSim.Framework
60 /// </summary> 60 /// </summary>
61 private AssetMetadata m_metadata; 61 private AssetMetadata m_metadata;
62 62
63 private int m_uploadAttempts;
64
63 // This is needed for .NET serialization!!! 65 // This is needed for .NET serialization!!!
64 // Do NOT "Optimize" away! 66 // Do NOT "Optimize" away!
65 public AssetBase() 67 public AssetBase()
@@ -197,6 +199,12 @@ namespace OpenSim.Framework
197 set { m_metadata.Type = value; } 199 set { m_metadata.Type = value; }
198 } 200 }
199 201
202 public int UploadAttempts
203 {
204 get { return m_uploadAttempts; }
205 set { m_uploadAttempts = value; }
206 }
207
200 /// <summary> 208 /// <summary>
201 /// Is this a region only asset, or does this exist on the asset server also 209 /// Is this a region only asset, or does this exist on the asset server also
202 /// </summary> 210 /// </summary>
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 18a5733..be15e1b 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -256,6 +256,21 @@ namespace OpenSim.Framework
256// } 256// }
257 } 257 }
258 258
259 /// <summary>
260 /// Invalidate all of the baked textures in the appearance, useful
261 /// if you know that none are valid
262 /// </summary>
263 public virtual void ResetBakedTextures()
264 {
265 SetDefaultTexture();
266
267 //for (int i = 0; i < BAKE_INDICES.Length; i++)
268 // {
269 // int idx = BAKE_INDICES[i];
270 // m_texture.FaceTextures[idx].TextureID = UUID.Zero;
271 // }
272 }
273
259 protected virtual void SetDefaultTexture() 274 protected virtual void SetDefaultTexture()
260 { 275 {
261 m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); 276 m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
@@ -399,27 +414,36 @@ namespace OpenSim.Framework
399 /// </summary> 414 /// </summary>
400 public List<AvatarAttachment> GetAttachments() 415 public List<AvatarAttachment> GetAttachments()
401 { 416 {
402 List<AvatarAttachment> alist = new List<AvatarAttachment>(); 417 lock (m_attachments)
403 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
404 { 418 {
405 foreach (AvatarAttachment attach in kvp.Value) 419 List<AvatarAttachment> alist = new List<AvatarAttachment>();
406 alist.Add(new AvatarAttachment(attach)); 420 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
407 } 421 {
422 foreach (AvatarAttachment attach in kvp.Value)
423 alist.Add(new AvatarAttachment(attach));
424 }
408 425
409 return alist; 426 return alist;
427 }
410 } 428 }
411 429
412 internal void AppendAttachment(AvatarAttachment attach) 430 internal void AppendAttachment(AvatarAttachment attach)
413 { 431 {
414 if (! m_attachments.ContainsKey(attach.AttachPoint)) 432 lock (m_attachments)
415 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>(); 433 {
416 m_attachments[attach.AttachPoint].Add(attach); 434 if (!m_attachments.ContainsKey(attach.AttachPoint))
435 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>();
436 m_attachments[attach.AttachPoint].Add(attach);
437 }
417 } 438 }
418 439
419 internal void ReplaceAttachment(AvatarAttachment attach) 440 internal void ReplaceAttachment(AvatarAttachment attach)
420 { 441 {
421 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>(); 442 lock (m_attachments)
422 m_attachments[attach.AttachPoint].Add(attach); 443 {
444 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>();
445 m_attachments[attach.AttachPoint].Add(attach);
446 }
423 } 447 }
424 448
425 /// <summary> 449 /// <summary>
@@ -435,9 +459,12 @@ namespace OpenSim.Framework
435 459
436 if (item == UUID.Zero) 460 if (item == UUID.Zero)
437 { 461 {
438 if (m_attachments.ContainsKey(attachpoint)) 462 lock (m_attachments)
439 m_attachments.Remove(attachpoint); 463 {
440 return; 464 if (m_attachments.ContainsKey(attachpoint))
465 m_attachments.Remove(attachpoint);
466 return;
467 }
441 } 468 }
442 469
443 // check if this is an append or a replace, 0x80 marks it as an append 470 // check if this is an append or a replace, 0x80 marks it as an append
@@ -455,37 +482,46 @@ namespace OpenSim.Framework
455 482
456 public int GetAttachpoint(UUID itemID) 483 public int GetAttachpoint(UUID itemID)
457 { 484 {
458 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments) 485 lock (m_attachments)
459 { 486 {
460 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); 487 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
461 if (index >= 0) 488 {
462 return kvp.Key; 489 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
463 } 490 if (index >= 0)
491 return kvp.Key;
492 }
464 493
465 return 0; 494 return 0;
495 }
466 } 496 }
467 497
468 public void DetachAttachment(UUID itemID) 498 public void DetachAttachment(UUID itemID)
469 { 499 {
470 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments) 500 lock (m_attachments)
471 { 501 {
472 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); 502 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
473 if (index >= 0)
474 { 503 {
475 // Remove it from the list of attachments at that attach point 504 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
476 m_attachments[kvp.Key].RemoveAt(index); 505 if (index >= 0)
506 {
507 // Remove it from the list of attachments at that attach point
508 m_attachments[kvp.Key].RemoveAt(index);
477 509
478 // And remove the list if there are no more attachments here 510 // And remove the list if there are no more attachments here
479 if (m_attachments[kvp.Key].Count == 0) 511 if (m_attachments[kvp.Key].Count == 0)
480 m_attachments.Remove(kvp.Key); 512 m_attachments.Remove(kvp.Key);
481 return; 513 return;
514 }
482 } 515 }
483 } 516 }
484 } 517 }
485 518
486 public void ClearAttachments() 519 public void ClearAttachments()
487 { 520 {
488 m_attachments.Clear(); 521 lock (m_attachments)
522 {
523 m_attachments.Clear();
524 }
489 } 525 }
490 526
491 #region Packing Functions 527 #region Packing Functions
@@ -522,11 +558,14 @@ namespace OpenSim.Framework
522 OSDBinary visualparams = new OSDBinary(m_visualparams); 558 OSDBinary visualparams = new OSDBinary(m_visualparams);
523 data["visualparams"] = visualparams; 559 data["visualparams"] = visualparams;
524 560
525 // Attachments 561 lock (m_attachments)
526 OSDArray attachs = new OSDArray(m_attachments.Count); 562 {
527 foreach (AvatarAttachment attach in GetAttachments()) 563 // Attachments
528 attachs.Add(attach.Pack()); 564 OSDArray attachs = new OSDArray(m_attachments.Count);
529 data["attachments"] = attachs; 565 foreach (AvatarAttachment attach in GetAttachments())
566 attachs.Add(attach.Pack());
567 data["attachments"] = attachs;
568 }
530 569
531 return data; 570 return data;
532 } 571 }
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs
index 97b3b60..42c0b18 100644
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ b/OpenSim/Framework/Communications/RestClient.cs
@@ -363,7 +363,7 @@ namespace OpenSim.Framework.Communications
363 _request = (HttpWebRequest) WebRequest.Create(buildUri()); 363 _request = (HttpWebRequest) WebRequest.Create(buildUri());
364 _request.KeepAlive = false; 364 _request.KeepAlive = false;
365 _request.ContentType = "application/xml"; 365 _request.ContentType = "application/xml";
366 _request.Timeout = 900000; 366 _request.Timeout = 30000;
367 _request.Method = RequestMethod; 367 _request.Method = RequestMethod;
368 _asyncException = null; 368 _asyncException = null;
369 _request.ContentLength = src.Length; 369 _request.ContentLength = src.Length;
diff --git a/OpenSim/Framework/ICallingCardModule.cs b/OpenSim/Framework/ICallingCardModule.cs
new file mode 100644
index 0000000..17e6de35
--- /dev/null
+++ b/OpenSim/Framework/ICallingCardModule.cs
@@ -0,0 +1,13 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using OpenMetaverse;
5using OpenSim.Framework;
6
7namespace OpenSim.Framework
8{
9 public interface ICallingCardModule
10 {
11 UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID);
12 }
13}
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index a6be157..3f77092 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -265,6 +265,9 @@ namespace OpenSim.Framework
265 public delegate void MoveInventoryItem( 265 public delegate void MoveInventoryItem(
266 IClientAPI remoteClient, List<InventoryItemBase> items); 266 IClientAPI remoteClient, List<InventoryItemBase> items);
267 267
268 public delegate void MoveItemsAndLeaveCopy(
269 IClientAPI remoteClient, List<InventoryItemBase> items, UUID destFolder);
270
268 public delegate void RemoveInventoryItem( 271 public delegate void RemoveInventoryItem(
269 IClientAPI remoteClient, List<UUID> itemIDs); 272 IClientAPI remoteClient, List<UUID> itemIDs);
270 273
@@ -460,9 +463,9 @@ namespace OpenSim.Framework
460 463
461 public delegate void AgentFOV(IClientAPI client, float verticalAngle); 464 public delegate void AgentFOV(IClientAPI client, float verticalAngle);
462 465
463 public delegate void MuteListEntryUpdate(IClientAPI client, UUID MuteID, string Name, int Flags,UUID AgentID); 466 public delegate void MuteListEntryUpdate(IClientAPI client, UUID MuteID, string Name, int type, uint flags);
464 467
465 public delegate void MuteListEntryRemove(IClientAPI client, UUID MuteID, string Name, UUID AgentID); 468 public delegate void MuteListEntryRemove(IClientAPI client, UUID MuteID, string Name);
466 469
467 public delegate void AvatarInterestReply(IClientAPI client,UUID target, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages); 470 public delegate void AvatarInterestReply(IClientAPI client,UUID target, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
468 471
@@ -792,6 +795,7 @@ namespace OpenSim.Framework
792 event RequestTaskInventory OnRequestTaskInventory; 795 event RequestTaskInventory OnRequestTaskInventory;
793 event UpdateInventoryItem OnUpdateInventoryItem; 796 event UpdateInventoryItem OnUpdateInventoryItem;
794 event CopyInventoryItem OnCopyInventoryItem; 797 event CopyInventoryItem OnCopyInventoryItem;
798 event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
795 event MoveInventoryItem OnMoveInventoryItem; 799 event MoveInventoryItem OnMoveInventoryItem;
796 event RemoveInventoryFolder OnRemoveInventoryFolder; 800 event RemoveInventoryFolder OnRemoveInventoryFolder;
797 event RemoveInventoryItem OnRemoveInventoryItem; 801 event RemoveInventoryItem OnRemoveInventoryItem;
@@ -962,6 +966,7 @@ namespace OpenSim.Framework
962 void InPacket(object NewPack); 966 void InPacket(object NewPack);
963 void ProcessInPacket(Packet NewPack); 967 void ProcessInPacket(Packet NewPack);
964 void Close(); 968 void Close();
969 void Close(bool sendStop);
965 void Kick(string message); 970 void Kick(string message);
966 971
967 /// <summary> 972 /// <summary>
@@ -993,7 +998,7 @@ namespace OpenSim.Framework
993 /// </summary> 998 /// </summary>
994 /// <param name="regionHandle"></param> 999 /// <param name="regionHandle"></param>
995 /// <param name="localID"></param> 1000 /// <param name="localID"></param>
996 void SendKillObject(ulong regionHandle, uint localID); 1001 void SendKillObject(ulong regionHandle, List<uint> localID);
997 1002
998 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); 1003 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
999 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); 1004 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
diff --git a/OpenSim/Framework/LandData.cs b/OpenSim/Framework/LandData.cs
index accf52e..3fb2fd6 100644
--- a/OpenSim/Framework/LandData.cs
+++ b/OpenSim/Framework/LandData.cs
@@ -62,7 +62,7 @@ namespace OpenSim.Framework
62 62
63 private uint _flags = (uint) ParcelFlags.AllowFly | (uint) ParcelFlags.AllowLandmark | 63 private uint _flags = (uint) ParcelFlags.AllowFly | (uint) ParcelFlags.AllowLandmark |
64 (uint) ParcelFlags.AllowAPrimitiveEntry | 64 (uint) ParcelFlags.AllowAPrimitiveEntry |
65 (uint) ParcelFlags.AllowDeedToGroup | (uint) ParcelFlags.AllowTerraform | 65 (uint) ParcelFlags.AllowDeedToGroup |
66 (uint) ParcelFlags.CreateObjects | (uint) ParcelFlags.AllowOtherScripts | 66 (uint) ParcelFlags.CreateObjects | (uint) ParcelFlags.AllowOtherScripts |
67 (uint) ParcelFlags.SoundLocal; 67 (uint) ParcelFlags.SoundLocal;
68 68
diff --git a/OpenSim/Framework/ParcelMediaCommandEnum.cs b/OpenSim/Framework/ParcelMediaCommandEnum.cs
index 93c41ec..e714382 100644
--- a/OpenSim/Framework/ParcelMediaCommandEnum.cs
+++ b/OpenSim/Framework/ParcelMediaCommandEnum.cs
@@ -27,7 +27,7 @@
27 27
28namespace OpenSim.Framework 28namespace OpenSim.Framework
29{ 29{
30 public enum ParcelMediaCommandEnum 30 public enum ParcelMediaCommandEnum : int
31 { 31 {
32 Stop = 0, 32 Stop = 0,
33 Pause = 1, 33 Pause = 1,
diff --git a/OpenSim/Framework/PluginLoader.cs b/OpenSim/Framework/PluginLoader.cs
index 819cb7b..cc80943 100644
--- a/OpenSim/Framework/PluginLoader.cs
+++ b/OpenSim/Framework/PluginLoader.cs
@@ -244,13 +244,22 @@ namespace OpenSim.Framework
244 // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0) 244 // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0)
245 // occasionally seems to corrupt its addin cache 245 // occasionally seems to corrupt its addin cache
246 // Hence, as a temporary solution we'll remove it before each startup 246 // Hence, as a temporary solution we'll remove it before each startup
247
248 string customDir = Environment.GetEnvironmentVariable ("MONO_ADDINS_REGISTRY");
249 string v0 = "addin-db-000";
250 string v1 = "addin-db-001";
251 if (customDir != null && customDir != String.Empty)
252 {
253 v0 = Path.Combine(customDir, v0);
254 v1 = Path.Combine(customDir, v1);
255 }
247 try 256 try
248 { 257 {
249 if (Directory.Exists("addin-db-000")) 258 if (Directory.Exists(v0))
250 Directory.Delete("addin-db-000", true); 259 Directory.Delete(v0, true);
251 260
252 if (Directory.Exists("addin-db-001")) 261 if (Directory.Exists(v1))
253 Directory.Delete("addin-db-001", true); 262 Directory.Delete(v1, true);
254 } 263 }
255 catch (IOException) 264 catch (IOException)
256 { 265 {
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index 927415e..20b9cf1 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -1333,7 +1333,7 @@ namespace OpenSim.Framework
1333 prim.Textures = this.Textures; 1333 prim.Textures = this.Textures;
1334 1334
1335 prim.Properties = new Primitive.ObjectProperties(); 1335 prim.Properties = new Primitive.ObjectProperties();
1336 prim.Properties.Name = "Primitive"; 1336 prim.Properties.Name = "Object";
1337 prim.Properties.Description = ""; 1337 prim.Properties.Description = "";
1338 prim.Properties.CreatorID = UUID.Zero; 1338 prim.Properties.CreatorID = UUID.Zero;
1339 prim.Properties.GroupID = UUID.Zero; 1339 prim.Properties.GroupID = UUID.Zero;
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index 680e702..d154bff 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -40,6 +40,7 @@ using OpenSim.Framework.Console;
40 40
41namespace OpenSim.Framework 41namespace OpenSim.Framework
42{ 42{
43 [Serializable]
43 public class RegionLightShareData : ICloneable 44 public class RegionLightShareData : ICloneable
44 { 45 {
45 public bool valid = false; 46 public bool valid = false;
diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
index 0ec4af5..f0ffc2c 100644
--- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
+++ b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
@@ -48,6 +48,9 @@ namespace OpenSim.Framework.RegionLoader.Web
48 48
49 public RegionInfo[] LoadRegions() 49 public RegionInfo[] LoadRegions()
50 { 50 {
51 int tries = 3;
52 int wait = 2000;
53
51 if (m_configSource == null) 54 if (m_configSource == null)
52 { 55 {
53 m_log.Error("[WEBLOADER]: Unable to load configuration source!"); 56 m_log.Error("[WEBLOADER]: Unable to load configuration source!");
@@ -64,35 +67,47 @@ namespace OpenSim.Framework.RegionLoader.Web
64 } 67 }
65 else 68 else
66 { 69 {
67 HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url); 70 while (tries > 0)
68 webRequest.Timeout = 30000; //30 Second Timeout
69 m_log.Debug("[WEBLOADER]: Sending Download Request...");
70 HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
71 m_log.Debug("[WEBLOADER]: Downloading Region Information From Remote Server...");
72 StreamReader reader = new StreamReader(webResponse.GetResponseStream());
73 string xmlSource = String.Empty;
74 string tempStr = reader.ReadLine();
75 while (tempStr != null)
76 {
77 xmlSource = xmlSource + tempStr;
78 tempStr = reader.ReadLine();
79 }
80 m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " +
81 xmlSource.Length);
82 XmlDocument xmlDoc = new XmlDocument();
83 xmlDoc.LoadXml(xmlSource);
84 if (xmlDoc.FirstChild.Name == "Regions")
85 { 71 {
86 RegionInfo[] regionInfos = new RegionInfo[xmlDoc.FirstChild.ChildNodes.Count]; 72 HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url);
87 int i; 73 webRequest.Timeout = 30000; //30 Second Timeout
88 for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) 74 m_log.Debug("[WEBLOADER]: Sending Download Request...");
75 HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
76 m_log.Debug("[WEBLOADER]: Downloading Region Information From Remote Server...");
77 StreamReader reader = new StreamReader(webResponse.GetResponseStream());
78 string xmlSource = String.Empty;
79 string tempStr = reader.ReadLine();
80 while (tempStr != null)
81 {
82 xmlSource = xmlSource + tempStr;
83 tempStr = reader.ReadLine();
84 }
85 m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " +
86 xmlSource.Length);
87 XmlDocument xmlDoc = new XmlDocument();
88 xmlDoc.LoadXml(xmlSource);
89 if (xmlDoc.FirstChild.Name == "Regions")
89 { 90 {
90 m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); 91 RegionInfo[] regionInfos = new RegionInfo[xmlDoc.FirstChild.ChildNodes.Count];
91 regionInfos[i] = 92 int i;
92 new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); 93 for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++)
94 {
95 m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml);
96 regionInfos[i] =
97 new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource);
98 }
99
100 if (i > 0)
101 return regionInfos;
93 } 102 }
94 103
95 return regionInfos; 104 m_log.Debug("[WEBLOADER]: Request yielded no regions.");
105 tries--;
106 if (tries > 0)
107 {
108 m_log.Debug("[WEBLOADER]: Retrying");
109 System.Threading.Thread.Sleep(wait);
110 }
96 } 111 }
97 return null; 112 return null;
98 } 113 }
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index cbab2db..8ff27c8 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -280,7 +280,7 @@ namespace OpenSim.Framework.Servers
280 280
281 EnhanceVersionInformation(); 281 EnhanceVersionInformation();
282 282
283 m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine); 283 m_log.Info("[STARTUP]: Careminster version: " + m_version + Environment.NewLine);
284 // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and 284 // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
285 // the clr version number doesn't match the project version number under Mono. 285 // the clr version number doesn't match the project version number under Mono.
286 //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); 286 //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs
index 41ece86..d5646d0 100644
--- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs
+++ b/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs
@@ -83,7 +83,7 @@ namespace OpenSim.Framework.Servers.HttpServer
83 } 83 }
84 catch (Exception e) 84 catch (Exception e)
85 { 85 {
86 m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); 86 m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: with {1} " + e.ToString(), requestUrl,obj);
87 } 87 }
88 finally 88 finally
89 { 89 {
diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs
index eab463c..077a1e8 100644
--- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs
+++ b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs
@@ -57,11 +57,27 @@ namespace OpenSim.Framework.Servers.HttpServer
57 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> 57 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
58 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) 58 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
59 { 59 {
60 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 100);
61 }
62 /// <summary>
63 /// Perform a synchronous REST request.
64 /// </summary>
65 /// <param name="verb"></param>
66 /// <param name="requestUrl"></param>
67 /// <param name="obj"> </param>
68 /// <param name="timeout"> </param>
69 /// <returns></returns>
70 ///
71 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
72 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
73 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
74 {
60 Type type = typeof (TRequest); 75 Type type = typeof (TRequest);
61 TResponse deserial = default(TResponse); 76 TResponse deserial = default(TResponse);
62 77
63 WebRequest request = WebRequest.Create(requestUrl); 78 WebRequest request = WebRequest.Create(requestUrl);
64 request.Method = verb; 79 request.Method = verb;
80 request.Timeout = pTimeout * 1000;
65 81
66 if ((verb == "POST") || (verb == "PUT")) 82 if ((verb == "POST") || (verb == "PUT"))
67 { 83 {
@@ -81,7 +97,6 @@ namespace OpenSim.Framework.Servers.HttpServer
81 97
82 int length = (int) buffer.Length; 98 int length = (int) buffer.Length;
83 request.ContentLength = length; 99 request.ContentLength = length;
84
85 Stream requestStream = null; 100 Stream requestStream = null;
86 try 101 try
87 { 102 {
@@ -103,7 +118,7 @@ namespace OpenSim.Framework.Servers.HttpServer
103 { 118 {
104 using (WebResponse resp = request.GetResponse()) 119 using (WebResponse resp = request.GetResponse())
105 { 120 {
106 if (resp.ContentLength > 0) 121 if (resp.ContentLength != 0)
107 { 122 {
108 Stream respStream = resp.GetResponseStream(); 123 Stream respStream = resp.GetResponseStream();
109 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); 124 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index c9d4c93..ce6ecf8 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -33,7 +33,7 @@ namespace OpenSim
33 private const Flavour VERSION_FLAVOUR = Flavour.Dev; 33 private const Flavour VERSION_FLAVOUR = Flavour.Dev;
34 34
35 public enum Flavour 35 public enum Flavour
36 { 36 {
37 Unknown, 37 Unknown,
38 Dev, 38 Dev,
39 RC1, 39 RC1,
@@ -49,7 +49,7 @@ namespace OpenSim
49 49
50 public static string GetVersionString(string versionNumber, Flavour flavour) 50 public static string GetVersionString(string versionNumber, Flavour flavour)
51 { 51 {
52 string versionString = "OpenSim " + versionNumber + " " + flavour; 52 string versionString = "Careminster " + versionNumber + " " + flavour;
53 return versionString.PadRight(VERSIONINFO_VERSION_LENGTH); 53 return versionString.PadRight(VERSIONINFO_VERSION_LENGTH);
54 } 54 }
55 55
diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs
index 25ae6b0..814758a 100644
--- a/OpenSim/Framework/TaskInventoryDictionary.cs
+++ b/OpenSim/Framework/TaskInventoryDictionary.cs
@@ -27,9 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Threading;
31using System.Reflection;
30using System.Xml; 32using System.Xml;
33using System.Diagnostics;
31using System.Xml.Schema; 34using System.Xml.Schema;
32using System.Xml.Serialization; 35using System.Xml.Serialization;
36using log4net;
33using OpenMetaverse; 37using OpenMetaverse;
34 38
35namespace OpenSim.Framework 39namespace OpenSim.Framework
@@ -45,6 +49,155 @@ namespace OpenSim.Framework
45 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 50
47 private static XmlSerializer tiiSerializer = new XmlSerializer(typeof (TaskInventoryItem)); 51 private static XmlSerializer tiiSerializer = new XmlSerializer(typeof (TaskInventoryItem));
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private Thread LockedByThread;
55 private string WriterStack;
56
57 private Dictionary<Thread, string> ReadLockers =
58 new Dictionary<Thread, string>();
59
60 /// <value>
61 /// An advanced lock for inventory data
62 /// </value>
63 private System.Threading.ReaderWriterLockSlim m_itemLock = new System.Threading.ReaderWriterLockSlim();
64
65 /// <summary>
66 /// Are we readlocked by the calling thread?
67 /// </summary>
68 public bool IsReadLockedByMe()
69 {
70 if (m_itemLock.RecursiveReadCount > 0)
71 {
72 return true;
73 }
74 else
75 {
76 return false;
77 }
78 }
79
80 /// <summary>
81 /// Lock our inventory list for reading (many can read, one can write)
82 /// </summary>
83 public void LockItemsForRead(bool locked)
84 {
85 if (locked)
86 {
87 if (m_itemLock.IsWriteLockHeld && LockedByThread != null)
88 {
89 if (!LockedByThread.IsAlive)
90 {
91 //Locked by dead thread, reset.
92 m_itemLock = new System.Threading.ReaderWriterLockSlim();
93 }
94 }
95
96 if (m_itemLock.RecursiveReadCount > 0)
97 {
98 m_log.Error("[TaskInventoryDictionary] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
99 try
100 {
101 StackTrace stackTrace = new StackTrace(); // get call stack
102 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
103
104 // write call stack method names
105 foreach (StackFrame stackFrame in stackFrames)
106 {
107 m_log.Error("[SceneObjectGroup.m_parts] "+(stackFrame.GetMethod().Name)); // write method name
108 }
109 }
110 catch
111 {}
112 m_itemLock.ExitReadLock();
113 }
114 if (m_itemLock.RecursiveWriteCount > 0)
115 {
116 m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed.");
117 m_itemLock.ExitWriteLock();
118 }
119
120 while (!m_itemLock.TryEnterReadLock(60000))
121 {
122 m_log.Error("Thread lock detected while trying to aquire READ lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
123 if (m_itemLock.IsWriteLockHeld)
124 {
125 m_itemLock = new System.Threading.ReaderWriterLockSlim();
126 System.Console.WriteLine("------------------------------------------");
127 System.Console.WriteLine("My call stack:\n" + Environment.StackTrace);
128 System.Console.WriteLine("------------------------------------------");
129 System.Console.WriteLine("Locker's call stack:\n" + WriterStack);
130 System.Console.WriteLine("------------------------------------------");
131 LockedByThread = null;
132 ReadLockers.Clear();
133 }
134 }
135 }
136 else
137 {
138 if (m_itemLock.RecursiveReadCount>0)
139 {
140 m_itemLock.ExitReadLock();
141 }
142 }
143 }
144
145 /// <summary>
146 /// Lock our inventory list for writing (many can read, one can write)
147 /// </summary>
148 public void LockItemsForWrite(bool locked)
149 {
150 if (locked)
151 {
152 //Enter a write lock, wait indefinately for one to open.
153 if (m_itemLock.RecursiveReadCount > 0)
154 {
155 m_log.Error("[TaskInventoryDictionary] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
156 m_itemLock.ExitReadLock();
157 }
158 if (m_itemLock.RecursiveWriteCount > 0)
159 {
160 m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed.");
161 m_itemLock.ExitWriteLock();
162 }
163 while (!m_itemLock.TryEnterWriteLock(60000))
164 {
165 if (m_itemLock.IsWriteLockHeld)
166 {
167 m_log.Error("Thread lock detected while trying to aquire WRITE lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
168 System.Console.WriteLine("------------------------------------------");
169 System.Console.WriteLine("My call stack:\n" + Environment.StackTrace);
170 System.Console.WriteLine("------------------------------------------");
171 System.Console.WriteLine("Locker's call stack:\n" + WriterStack);
172 System.Console.WriteLine("------------------------------------------");
173 }
174 else
175 {
176 m_log.Error("Thread lock detected while trying to aquire WRITE lock in TaskInventoryDictionary. Locked by a reader. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
177 System.Console.WriteLine("------------------------------------------");
178 System.Console.WriteLine("My call stack:\n" + Environment.StackTrace);
179 System.Console.WriteLine("------------------------------------------");
180 foreach (KeyValuePair<Thread, string> kvp in ReadLockers)
181 {
182 System.Console.WriteLine("Locker name {0} call stack:\n" + kvp.Value, kvp.Key.Name);
183 System.Console.WriteLine("------------------------------------------");
184 }
185 }
186 m_itemLock = new System.Threading.ReaderWriterLockSlim();
187 ReadLockers.Clear();
188 }
189
190 LockedByThread = Thread.CurrentThread;
191 WriterStack = Environment.StackTrace;
192 }
193 else
194 {
195 if (m_itemLock.RecursiveWriteCount > 0)
196 {
197 m_itemLock.ExitWriteLock();
198 }
199 }
200 }
48 201
49 #region ICloneable Members 202 #region ICloneable Members
50 203
@@ -52,13 +205,12 @@ namespace OpenSim.Framework
52 { 205 {
53 TaskInventoryDictionary clone = new TaskInventoryDictionary(); 206 TaskInventoryDictionary clone = new TaskInventoryDictionary();
54 207
55 lock (this) 208 m_itemLock.EnterReadLock();
209 foreach (UUID uuid in Keys)
56 { 210 {
57 foreach (UUID uuid in Keys) 211 clone.Add(uuid, (TaskInventoryItem) this[uuid].Clone());
58 {
59 clone.Add(uuid, (TaskInventoryItem) this[uuid].Clone());
60 }
61 } 212 }
213 m_itemLock.ExitReadLock();
62 214
63 return clone; 215 return clone;
64 } 216 }
diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs
index 30d775c..248502e 100644
--- a/OpenSim/Framework/TaskInventoryItem.cs
+++ b/OpenSim/Framework/TaskInventoryItem.cs
@@ -121,7 +121,7 @@ namespace OpenSim.Framework
121 private UUID _permsGranter; 121 private UUID _permsGranter;
122 private int _permsMask; 122 private int _permsMask;
123 private int _type = 0; 123 private int _type = 0;
124 private UUID _oldID; 124 private UUID _oldID = UUID.Zero;
125 125
126 private bool _ownerChanged = false; 126 private bool _ownerChanged = false;
127 127
@@ -404,7 +404,8 @@ namespace OpenSim.Framework
404 /// <param name="partID">The new part ID to which this item belongs</param> 404 /// <param name="partID">The new part ID to which this item belongs</param>
405 public void ResetIDs(UUID partID) 405 public void ResetIDs(UUID partID)
406 { 406 {
407 OldItemID = ItemID; 407 if (_oldID == UUID.Zero)
408 _oldID = ItemID;
408 ItemID = UUID.Random(); 409 ItemID = UUID.Random();
409 ParentPartID = partID; 410 ParentPartID = partID;
410 ParentID = partID; 411 ParentID = partID;
diff --git a/OpenSim/Framework/UndoStack.cs b/OpenSim/Framework/UndoStack.cs
index 4d800ae..4cd779a 100644
--- a/OpenSim/Framework/UndoStack.cs
+++ b/OpenSim/Framework/UndoStack.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
29 30
30namespace OpenSim.Framework 31namespace OpenSim.Framework
31{ 32{
@@ -36,33 +37,30 @@ namespace OpenSim.Framework
36 [Serializable] 37 [Serializable]
37 public class UndoStack<T> 38 public class UndoStack<T>
38 { 39 {
39 private int m_new = 1; 40 private List<T> m_undolist;
40 private int m_old = 0; 41 private int m_max;
41 private T[] m_Undos;
42 42
43 public UndoStack(int capacity) 43 public UndoStack(int capacity)
44 { 44 {
45 m_Undos = new T[capacity + 1]; 45 m_undolist = new List<T>();
46 m_max = capacity;
46 } 47 }
47 48
48 public bool IsFull 49 public bool IsFull
49 { 50 {
50 get { return m_new == m_old; } 51 get { return m_undolist.Count >= m_max; }
51 } 52 }
52 53
53 public int Capacity 54 public int Capacity
54 { 55 {
55 get { return m_Undos.Length - 1; } 56 get { return m_max; }
56 } 57 }
57 58
58 public int Count 59 public int Count
59 { 60 {
60 get 61 get
61 { 62 {
62 int count = m_new - m_old - 1; 63 return m_undolist.Count;
63 if (count < 0)
64 count += m_Undos.Length;
65 return count;
66 } 64 }
67 } 65 }
68 66
@@ -70,45 +68,39 @@ namespace OpenSim.Framework
70 { 68 {
71 if (IsFull) 69 if (IsFull)
72 { 70 {
73 m_old++; 71 m_undolist.RemoveAt(0);
74 if (m_old >= m_Undos.Length)
75 m_old -= m_Undos.Length;
76 } 72 }
77 if (++m_new >= m_Undos.Length) 73 m_undolist.Add(item);
78 m_new -= m_Undos.Length;
79 m_Undos[m_new] = item;
80 } 74 }
81 75
82 public T Pop() 76 public T Pop()
83 { 77 {
84 if (Count > 0) 78 if (m_undolist.Count > 0)
85 { 79 {
86 T deleted = m_Undos[m_new]; 80 int ind = m_undolist.Count - 1;
87 m_Undos[m_new--] = default(T); 81 T item = m_undolist[ind];
88 if (m_new < 0) 82 m_undolist.RemoveAt(ind);
89 m_new += m_Undos.Length; 83 return item;
90 return deleted;
91 } 84 }
92 else 85 else
93 throw new InvalidOperationException("Cannot pop from emtpy stack"); 86 throw new InvalidOperationException("Cannot pop from empty stack");
94 } 87 }
95 88
96 public T Peek() 89 public T Peek()
97 { 90 {
98 return m_Undos[m_new]; 91 if (m_undolist.Count > 0)
92 {
93 return m_undolist[m_undolist.Count - 1];
94 }
95 else
96 {
97 return default(T);
98 }
99 } 99 }
100 100
101 public void Clear() 101 public void Clear()
102 { 102 {
103 if (Count > 0) 103 m_undolist.Clear();
104 {
105 for (int i = 0; i < m_Undos.Length; i++)
106 {
107 m_Undos[i] = default(T);
108 }
109 m_new = 1;
110 m_old = 0;
111 }
112 } 104 }
113 } 105 }
114} 106}
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 8d1671a..877b0c2 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1016,19 +1016,19 @@ namespace OpenSim.Framework
1016 { 1016 {
1017 string os = String.Empty; 1017 string os = String.Empty;
1018 1018
1019 if (Environment.OSVersion.Platform != PlatformID.Unix) 1019// if (Environment.OSVersion.Platform != PlatformID.Unix)
1020 { 1020// {
1021 os = Environment.OSVersion.ToString(); 1021// os = Environment.OSVersion.ToString();
1022 } 1022// }
1023 else 1023// else
1024 { 1024// {
1025 os = ReadEtcIssue(); 1025// os = ReadEtcIssue();
1026 } 1026// }
1027 1027//
1028 if (os.Length > 45) 1028// if (os.Length > 45)
1029 { 1029// {
1030 os = os.Substring(0, 45); 1030// os = os.Substring(0, 45);
1031 } 1031// }
1032 1032
1033 return os; 1033 return os;
1034 } 1034 }
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs
index 0f34e83..3389ecb 100644
--- a/OpenSim/Framework/Watchdog.cs
+++ b/OpenSim/Framework/Watchdog.cs
@@ -52,7 +52,7 @@ namespace OpenSim.Framework
52 public ThreadWatchdogInfo(Thread thread) 52 public ThreadWatchdogInfo(Thread thread)
53 { 53 {
54 Thread = thread; 54 Thread = thread;
55 LastTick = Environment.TickCount & Int32.MaxValue; 55 LastTick = Environment.TickCount;
56 } 56 }
57 } 57 }
58 58
@@ -127,7 +127,7 @@ namespace OpenSim.Framework
127 m_threads.Add(threadInfo.Thread.ManagedThreadId, threadInfo); 127 m_threads.Add(threadInfo.Thread.ManagedThreadId, threadInfo);
128 } 128 }
129 129
130 private static bool RemoveThread(int threadID) 130 public static bool RemoveThread(int threadID)
131 { 131 {
132 lock (m_threads) 132 lock (m_threads)
133 return m_threads.Remove(threadID); 133 return m_threads.Remove(threadID);
@@ -144,7 +144,7 @@ namespace OpenSim.Framework
144 try 144 try
145 { 145 {
146 if (m_threads.TryGetValue(threadID, out threadInfo)) 146 if (m_threads.TryGetValue(threadID, out threadInfo))
147 threadInfo.LastTick = Environment.TickCount & Int32.MaxValue; 147 threadInfo.LastTick = Environment.TickCount;
148 else 148 else
149 AddThread(new ThreadWatchdogInfo(Thread.CurrentThread)); 149 AddThread(new ThreadWatchdogInfo(Thread.CurrentThread));
150 } 150 }
@@ -170,7 +170,7 @@ namespace OpenSim.Framework
170 170
171 lock (m_threads) 171 lock (m_threads)
172 { 172 {
173 int now = Environment.TickCount & Int32.MaxValue; 173 int now = Environment.TickCount;
174 174
175 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) 175 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values)
176 { 176 {
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index e3b8573..7a188fd 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -444,7 +444,7 @@ namespace OpenSim
444 if (alert != null) 444 if (alert != null)
445 presence.ControllingClient.Kick(alert); 445 presence.ControllingClient.Kick(alert);
446 else 446 else
447 presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); 447 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
448 448
449 // ...and close on our side 449 // ...and close on our side
450 presence.Scene.IncomingCloseAgent(presence.UUID); 450 presence.Scene.IncomingCloseAgent(presence.UUID);
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index 1652b82..b74a392 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -88,6 +88,10 @@ namespace OpenSim
88 88
89 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>(); 89 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>();
90 90
91 private List<string> m_permsModules;
92
93 private bool m_securePermissionsLoading = true;
94
91 /// <value> 95 /// <value>
92 /// The config information passed into the OpenSimulator region server. 96 /// The config information passed into the OpenSimulator region server.
93 /// </value> 97 /// </value>
@@ -185,6 +189,11 @@ namespace OpenSim
185 CreatePIDFile(pidFile); 189 CreatePIDFile(pidFile);
186 190
187 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty); 191 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty);
192
193 m_securePermissionsLoading = startupConfig.GetBoolean("SecurePermissionsLoading", true);
194
195 string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule");
196 m_permsModules = new List<string>(permissionModules.Split(','));
188 } 197 }
189 198
190 // Load the simulation data service 199 // Load the simulation data service
@@ -213,6 +222,12 @@ namespace OpenSim
213 m_moduleLoader = new ModuleLoader(m_config.Source); 222 m_moduleLoader = new ModuleLoader(m_config.Source);
214 223
215 LoadPlugins(); 224 LoadPlugins();
225
226 if (m_plugins.Count == 0) // We failed to load any modules. Mono Addins glitch!
227 {
228 Environment.Exit(1);
229 }
230
216 foreach (IApplicationPlugin plugin in m_plugins) 231 foreach (IApplicationPlugin plugin in m_plugins)
217 { 232 {
218 plugin.PostInitialise(); 233 plugin.PostInitialise();
@@ -360,7 +375,41 @@ namespace OpenSim
360 } 375 }
361 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing..."); 376 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing...");
362 377
378 if (m_securePermissionsLoading)
379 {
380 foreach (string s in m_permsModules)
381 {
382 if (!scene.RegionModules.ContainsKey(s))
383 {
384 bool found = false;
385 foreach (IRegionModule m in modules)
386 {
387 if (m.Name == s)
388 {
389 found = true;
390 }
391 }
392 if (!found)
393 {
394 m_log.Fatal("[MODULES]: Required module " + s + " not found.");
395 Environment.Exit(0);
396 }
397 }
398 }
399 }
400
363 scene.SetModuleInterfaces(); 401 scene.SetModuleInterfaces();
402// First Step of bootreport sequence
403 if (scene.SnmpService != null)
404 {
405 scene.SnmpService.ColdStart(1,scene);
406 scene.SnmpService.LinkDown(scene);
407 }
408
409 if (scene.SnmpService != null)
410 {
411 scene.SnmpService.BootInfo("Loading prins", scene);
412 }
364 413
365 // Prims have to be loaded after module configuration since some modules may be invoked during the load 414 // Prims have to be loaded after module configuration since some modules may be invoked during the load
366 scene.LoadPrimsFromStorage(regionInfo.originRegionID); 415 scene.LoadPrimsFromStorage(regionInfo.originRegionID);
@@ -368,6 +417,10 @@ namespace OpenSim
368 // TODO : Try setting resource for region xstats here on scene 417 // TODO : Try setting resource for region xstats here on scene
369 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo)); 418 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo));
370 419
420 if (scene.SnmpService != null)
421 {
422 scene.SnmpService.BootInfo("Grid Registration in progress", scene);
423 }
371 try 424 try
372 { 425 {
373 scene.RegisterRegionWithGrid(); 426 scene.RegisterRegionWithGrid();
@@ -378,11 +431,20 @@ namespace OpenSim
378 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}", 431 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
379 e.Message, e.StackTrace); 432 e.Message, e.StackTrace);
380 433
434 if (scene.SnmpService != null)
435 {
436 scene.SnmpService.Critical("Grid registration failed. Startup aborted.", scene);
437 }
381 // Carrying on now causes a lot of confusion down the 438 // Carrying on now causes a lot of confusion down the
382 // line - we need to get the user's attention 439 // line - we need to get the user's attention
383 Environment.Exit(1); 440 Environment.Exit(1);
384 } 441 }
385 442
443 if (scene.SnmpService != null)
444 {
445 scene.SnmpService.BootInfo("Grid Registration done", scene);
446 }
447
386 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); 448 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
387 scene.EventManager.TriggerParcelPrimCountUpdate(); 449 scene.EventManager.TriggerParcelPrimCountUpdate();
388 450
@@ -390,6 +452,11 @@ namespace OpenSim
390 // scripting engines. 452 // scripting engines.
391 scene.CreateScriptInstances(); 453 scene.CreateScriptInstances();
392 454
455 if (scene.SnmpService != null)
456 {
457 scene.SnmpService.BootInfo("ScriptEngine started", scene);
458 }
459
393 m_sceneManager.Add(scene); 460 m_sceneManager.Add(scene);
394 461
395 if (m_autoCreateClientStack) 462 if (m_autoCreateClientStack)
@@ -398,6 +465,10 @@ namespace OpenSim
398 clientServer.Start(); 465 clientServer.Start();
399 } 466 }
400 467
468 if (scene.SnmpService != null)
469 {
470 scene.SnmpService.BootInfo("Initializing region modules", scene);
471 }
401 if (do_post_init) 472 if (do_post_init)
402 { 473 {
403 foreach (IRegionModule module in modules) 474 foreach (IRegionModule module in modules)
@@ -409,6 +480,12 @@ namespace OpenSim
409 480
410 mscene = scene; 481 mscene = scene;
411 482
483 if (scene.SnmpService != null)
484 {
485 scene.SnmpService.BootInfo("The region is operational", scene);
486 scene.SnmpService.LinkUp(scene);
487 }
488
412 scene.StartTimer(); 489 scene.StartTimer();
413 490
414 return clientServer; 491 return clientServer;
@@ -417,6 +494,11 @@ namespace OpenSim
417 private void ShutdownRegion(Scene scene) 494 private void ShutdownRegion(Scene scene)
418 { 495 {
419 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName); 496 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
497 if (scene.SnmpService != null)
498 {
499 scene.SnmpService.BootInfo("The region is shutting down", scene);
500 scene.SnmpService.LinkDown(scene);
501 }
420 IRegionModulesController controller; 502 IRegionModulesController controller;
421 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller)) 503 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller))
422 { 504 {
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index e9e2dca..9dd6663 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -202,6 +202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
202 m_stopPacket = TexturePacketCount(); 202 m_stopPacket = TexturePacketCount();
203 } 203 }
204 204
205 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
206 if (m_stopPacket == 1 && Layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
207
205 m_currentPacket = StartPacket; 208 m_currentPacket = StartPacket;
206 } 209 }
207 } 210 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index ee4f04e..e416d05 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
155 public event RequestTaskInventory OnRequestTaskInventory; 155 public event RequestTaskInventory OnRequestTaskInventory;
156 public event UpdateInventoryItem OnUpdateInventoryItem; 156 public event UpdateInventoryItem OnUpdateInventoryItem;
157 public event CopyInventoryItem OnCopyInventoryItem; 157 public event CopyInventoryItem OnCopyInventoryItem;
158 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
158 public event MoveInventoryItem OnMoveInventoryItem; 159 public event MoveInventoryItem OnMoveInventoryItem;
159 public event RemoveInventoryItem OnRemoveInventoryItem; 160 public event RemoveInventoryItem OnRemoveInventoryItem;
160 public event RemoveInventoryFolder OnRemoveInventoryFolder; 161 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -327,7 +328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
327 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 328 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
328 /// ownerless phantom. 329 /// ownerless phantom.
329 /// 330 ///
330 /// All manipulation of this set has to occur under a lock 331 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
331 /// 332 ///
332 /// </value> 333 /// </value>
333 protected HashSet<uint> m_killRecord; 334 protected HashSet<uint> m_killRecord;
@@ -335,6 +336,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335// protected HashSet<uint> m_attachmentsSent; 336// protected HashSet<uint> m_attachmentsSent;
336 337
337 private int m_moneyBalance; 338 private int m_moneyBalance;
339 private bool m_deliverPackets = true;
338 private int m_animationSequenceNumber = 1; 340 private int m_animationSequenceNumber = 1;
339 private bool m_SendLogoutPacketWhenClosing = true; 341 private bool m_SendLogoutPacketWhenClosing = true;
340 private AgentUpdateArgs lastarg; 342 private AgentUpdateArgs lastarg;
@@ -377,6 +379,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
377 get { return m_startpos; } 379 get { return m_startpos; }
378 set { m_startpos = value; } 380 set { m_startpos = value; }
379 } 381 }
382 public bool DeliverPackets
383 {
384 get { return m_deliverPackets; }
385 set {
386 m_deliverPackets = value;
387 m_udpClient.m_deliverPackets = value;
388 }
389 }
380 public UUID AgentId { get { return m_agentId; } } 390 public UUID AgentId { get { return m_agentId; } }
381 public UUID ActiveGroupId { get { return m_activeGroupID; } } 391 public UUID ActiveGroupId { get { return m_activeGroupID; } }
382 public string ActiveGroupName { get { return m_activeGroupName; } } 392 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -475,18 +485,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
475 485
476 #region Client Methods 486 #region Client Methods
477 487
488
478 /// <summary> 489 /// <summary>
479 /// Shut down the client view 490 /// Shut down the client view
480 /// </summary> 491 /// </summary>
481 public void Close() 492 public void Close()
482 { 493 {
494 Close(true);
495 }
496
497 /// <summary>
498 /// Shut down the client view
499 /// </summary>
500 public void Close(bool sendStop)
501 {
483 m_log.DebugFormat( 502 m_log.DebugFormat(
484 "[CLIENT]: Close has been called for {0} attached to scene {1}", 503 "[CLIENT]: Close has been called for {0} attached to scene {1}",
485 Name, m_scene.RegionInfo.RegionName); 504 Name, m_scene.RegionInfo.RegionName);
486 505
487 // Send the STOP packet 506 if (sendStop)
488 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 507 {
489 OutPacket(disable, ThrottleOutPacketType.Unknown); 508 // Send the STOP packet
509 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
510 OutPacket(disable, ThrottleOutPacketType.Unknown);
511 }
490 512
491 IsActive = false; 513 IsActive = false;
492 514
@@ -767,7 +789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 reply.ChatData.OwnerID = fromAgentID; 789 reply.ChatData.OwnerID = fromAgentID;
768 reply.ChatData.SourceID = fromAgentID; 790 reply.ChatData.SourceID = fromAgentID;
769 791
770 OutPacket(reply, ThrottleOutPacketType.Task); 792 OutPacket(reply, ThrottleOutPacketType.Unknown);
771 } 793 }
772 794
773 /// <summary> 795 /// <summary>
@@ -1053,6 +1075,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1053 public virtual void SendLayerData(float[] map) 1075 public virtual void SendLayerData(float[] map)
1054 { 1076 {
1055 Util.FireAndForget(DoSendLayerData, map); 1077 Util.FireAndForget(DoSendLayerData, map);
1078
1079 // Send it sync, and async. It's not that much data
1080 // and it improves user experience just so much!
1081 DoSendLayerData(map);
1056 } 1082 }
1057 1083
1058 /// <summary> 1084 /// <summary>
@@ -1065,16 +1091,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1065 1091
1066 try 1092 try
1067 { 1093 {
1068 //for (int y = 0; y < 16; y++) 1094 for (int y = 0; y < 16; y++)
1069 //{ 1095 {
1070 // for (int x = 0; x < 16; x++) 1096 for (int x = 0; x < 16; x+=4)
1071 // { 1097 {
1072 // SendLayerData(x, y, map); 1098 SendLayerPacket(x, y, map);
1073 // } 1099 }
1074 //} 1100 }
1075
1076 // Send LayerData in a spiral pattern. Fun!
1077 SendLayerTopRight(map, 0, 0, 15, 15);
1078 } 1101 }
1079 catch (Exception e) 1102 catch (Exception e)
1080 { 1103 {
@@ -1082,51 +1105,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1082 } 1105 }
1083 } 1106 }
1084 1107
1085 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1086 {
1087 // Row
1088 for (int i = x1; i <= x2; i++)
1089 SendLayerData(i, y1, map);
1090
1091 // Column
1092 for (int j = y1 + 1; j <= y2; j++)
1093 SendLayerData(x2, j, map);
1094
1095 if (x2 - x1 > 0)
1096 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1097 }
1098
1099 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1100 {
1101 // Row in reverse
1102 for (int i = x2; i >= x1; i--)
1103 SendLayerData(i, y2, map);
1104
1105 // Column in reverse
1106 for (int j = y2 - 1; j >= y1; j--)
1107 SendLayerData(x1, j, map);
1108
1109 if (x2 - x1 > 0)
1110 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1111 }
1112
1113 /// <summary> 1108 /// <summary>
1114 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1109 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1115 /// </summary> 1110 /// </summary>
1116 /// <param name="map">heightmap</param> 1111 /// <param name="map">heightmap</param>
1117 /// <param name="px">X coordinate for patches 0..12</param> 1112 /// <param name="px">X coordinate for patches 0..12</param>
1118 /// <param name="py">Y coordinate for patches 0..15</param> 1113 /// <param name="py">Y coordinate for patches 0..15</param>
1119 // private void SendLayerPacket(float[] map, int y, int x) 1114 private void SendLayerPacket(int x, int y, float[] map)
1120 // { 1115 {
1121 // int[] patches = new int[4]; 1116 int[] patches = new int[4];
1122 // patches[0] = x + 0 + y * 16; 1117 patches[0] = x + 0 + y * 16;
1123 // patches[1] = x + 1 + y * 16; 1118 patches[1] = x + 1 + y * 16;
1124 // patches[2] = x + 2 + y * 16; 1119 patches[2] = x + 2 + y * 16;
1125 // patches[3] = x + 3 + y * 16; 1120 patches[3] = x + 3 + y * 16;
1126 1121
1127 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1122 float[] heightmap = (map.Length == 65536) ?
1128 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1123 map :
1129 // } 1124 LLHeightFieldMoronize(map);
1125
1126 try
1127 {
1128 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1129 OutPacket(layerpack, ThrottleOutPacketType.Land);
1130 }
1131 catch
1132 {
1133 for (int px = x ; px < x + 4 ; px++)
1134 SendLayerData(px, y, map);
1135 }
1136 }
1130 1137
1131 /// <summary> 1138 /// <summary>
1132 /// Sends a specified patch to a client 1139 /// Sends a specified patch to a client
@@ -1146,7 +1153,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1153 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1147 layerpack.Header.Reliable = true; 1154 layerpack.Header.Reliable = true;
1148 1155
1149 OutPacket(layerpack, ThrottleOutPacketType.Land); 1156 OutPacket(layerpack, ThrottleOutPacketType.Task);
1150 } 1157 }
1151 catch (Exception e) 1158 catch (Exception e)
1152 { 1159 {
@@ -1507,37 +1514,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1507 OutPacket(pc, ThrottleOutPacketType.Unknown); 1514 OutPacket(pc, ThrottleOutPacketType.Unknown);
1508 } 1515 }
1509 1516
1510 public void SendKillObject(ulong regionHandle, uint localID) 1517 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1511 { 1518 {
1512// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1519// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1513 1520
1514 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1521 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1515 // TODO: don't create new blocks if recycling an old packet 1522 // TODO: don't create new blocks if recycling an old packet
1516 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1523 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1517 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1524 for (int i = 0 ; i < localIDs.Count ; i++ )
1518 kill.ObjectData[0].ID = localID; 1525 {
1526 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1527 kill.ObjectData[i].ID = localIDs[i];
1528 }
1519 kill.Header.Reliable = true; 1529 kill.Header.Reliable = true;
1520 kill.Header.Zerocoded = true; 1530 kill.Header.Zerocoded = true;
1521 1531
1522 if (m_scene.GetScenePresence(localID) == null) 1532 lock (m_killRecord)
1523 { 1533 {
1524 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 1534 if (localIDs.Count == 1)
1525 // condition where a kill can be processed before an out-of-date update for the same object. 1535 {
1526 lock (m_killRecord) 1536 if (m_scene.GetScenePresence(localIDs[0]) != null)
1537 {
1538 OutPacket(kill, ThrottleOutPacketType.State);
1539 return;
1540 }
1541 m_killRecord.Add(localIDs[0]);
1542 }
1543 else
1527 { 1544 {
1528 m_killRecord.Add(localID); 1545 lock (m_entityUpdates.SyncRoot)
1529 1546 {
1530 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1547 foreach (uint localID in localIDs)
1531 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1548 m_killRecord.Add(localID);
1532 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1549 }
1533 // scene objects in a viewer until that viewer is relogged in.
1534 OutPacket(kill, ThrottleOutPacketType.Task);
1535 } 1550 }
1536 } 1551 }
1537 else 1552
1538 { 1553 // The throttle queue used here must match that being used for
1539 OutPacket(kill, ThrottleOutPacketType.State); 1554 // updates. Otherwise, there is a chance that a kill packet put
1540 } 1555 // on a separate queue will be sent to the client before an
1556 // existing update packet on another queue. Receiving updates
1557 // after kills results in unowned and undeletable
1558 // scene objects in a viewer until that viewer is relogged in.
1559 OutPacket(kill, ThrottleOutPacketType.Task);
1541 } 1560 }
1542 1561
1543 /// <summary> 1562 /// <summary>
@@ -2250,6 +2269,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2250 OutPacket(sound, ThrottleOutPacketType.Task); 2269 OutPacket(sound, ThrottleOutPacketType.Task);
2251 } 2270 }
2252 2271
2272 public void SendTransferAbort(TransferRequestPacket transferRequest)
2273 {
2274 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2275 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2276 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2277 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2278 OutPacket(abort, ThrottleOutPacketType.Task);
2279 }
2280
2253 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2281 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2254 { 2282 {
2255 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2283 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3551,6 +3579,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3551 /// </summary> 3579 /// </summary>
3552 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3580 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3553 { 3581 {
3582 if (entity is SceneObjectPart)
3583 {
3584 SceneObjectPart e = (SceneObjectPart)entity;
3585 SceneObjectGroup g = e.ParentGroup;
3586 if (g.RootPart.Shape.State > 30) // HUD
3587 if (g.OwnerID != AgentId)
3588 return; // Don't send updates for other people's HUDs
3589 }
3590
3554 double priority = m_prioritizer.GetUpdatePriority(this, entity); 3591 double priority = m_prioritizer.GetUpdatePriority(this, entity);
3555 3592
3556 lock (m_entityUpdates.SyncRoot) 3593 lock (m_entityUpdates.SyncRoot)
@@ -3567,232 +3604,257 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3567 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; 3604 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
3568 int updatesThisCall = 0; 3605 int updatesThisCall = 0;
3569 3606
3570 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3607 float avgTimeDilation = 0;
3571 // condition where a kill can be processed before an out-of-date update for the same object. 3608
3572 lock (m_killRecord) 3609 EntityUpdate update;
3610 while (updatesThisCall < maxUpdates)
3573 { 3611 {
3574 float avgTimeDilation = 1.0f; 3612 lock (m_entityUpdates.SyncRoot)
3575 EntityUpdate update; 3613 if (!m_entityUpdates.TryDequeue(out update))
3576 while (updatesThisCall < maxUpdates) 3614 break;
3615
3616 avgTimeDilation += update.TimeDilation;
3617 avgTimeDilation *= 0.5f;
3618
3619 if (update.Entity is SceneObjectPart)
3577 { 3620 {
3578 lock (m_entityUpdates.SyncRoot) 3621 SceneObjectPart part = (SceneObjectPart)update.Entity;
3579 if (!m_entityUpdates.TryDequeue(out update))
3580 break;
3581 avgTimeDilation += update.TimeDilation;
3582 avgTimeDilation *= 0.5f;
3583 3622
3584 if (update.Entity is SceneObjectPart) 3623 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3624 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3625 // safety measure.
3626 //
3627 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3628 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3629 // updates and kills on different threads with different scheduling strategies, hence this protection.
3630 //
3631 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3632 // after the root prim has been deleted.
3633 lock (m_killRecord)
3585 { 3634 {
3586 SceneObjectPart part = (SceneObjectPart)update.Entity;
3587
3588 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3589 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3590 // safety measure.
3591 //
3592 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3593 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3594 // updates and kills on different threads with different scheduling strategies, hence this protection.
3595 //
3596 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3597 // after the root prim has been deleted.
3598 if (m_killRecord.Contains(part.LocalId)) 3635 if (m_killRecord.Contains(part.LocalId))
3599 {
3600 // m_log.WarnFormat(
3601 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3602 // part.LocalId, Name);
3603 continue; 3636 continue;
3604 } 3637 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3605 3638 continue;
3606 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3639 }
3640
3641 if (part.ParentGroup.IsDeleted)
3642 continue;
3643
3644 if (part.ParentGroup.IsAttachment)
3645 { // Someone else's HUD, why are we getting these?
3646 if (part.ParentGroup.OwnerID != AgentId &&
3647 part.ParentGroup.RootPart.Shape.State >= 30)
3648 continue;
3649 ScenePresence sp;
3650 // Owner is not in the sim, don't update it to
3651 // anyone
3652 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3653 continue;
3654
3655 List<SceneObjectGroup> atts = sp.Attachments;
3656 bool found = false;
3657 foreach (SceneObjectGroup att in atts)
3607 { 3658 {
3608 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3659 if (att == part.ParentGroup)
3609 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3610 { 3660 {
3611 part.Shape.LightEntry = false; 3661 found = true;
3662 break;
3612 } 3663 }
3613 } 3664 }
3665
3666 // It's an attachment of a valid avatar, but
3667 // doesn't seem to be attached, skip
3668 if (!found)
3669 continue;
3614 } 3670 }
3615 3671
3616 ++updatesThisCall; 3672 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3617
3618 #region UpdateFlags to packet type conversion
3619
3620 PrimUpdateFlags updateFlags = update.Flags;
3621
3622 bool canUseCompressed = true;
3623 bool canUseImproved = true;
3624
3625 // Compressed object updates only make sense for LL primitives
3626 if (!(update.Entity is SceneObjectPart))
3627 {
3628 canUseCompressed = false;
3629 }
3630
3631 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3632 {
3633 canUseCompressed = false;
3634 canUseImproved = false;
3635 }
3636 else
3637 { 3673 {
3638 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3674 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3639 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3675 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3640 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3641 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3642 { 3676 {
3643 canUseCompressed = false; 3677 part.Shape.LightEntry = false;
3644 }
3645
3646 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3647 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3648 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3649 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3650 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3651 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3652 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3653 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3654 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3655 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3656 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3657 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3658 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3659 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3660 {
3661 canUseImproved = false;
3662 } 3678 }
3663 } 3679 }
3664 3680 }
3665 #endregion UpdateFlags to packet type conversion 3681
3666 3682 ++updatesThisCall;
3667 #region Block Construction 3683
3668 3684 #region UpdateFlags to packet type conversion
3669 // TODO: Remove this once we can build compressed updates 3685
3686 PrimUpdateFlags updateFlags = update.Flags;
3687
3688 bool canUseCompressed = true;
3689 bool canUseImproved = true;
3690
3691 // Compressed object updates only make sense for LL primitives
3692 if (!(update.Entity is SceneObjectPart))
3693 {
3670 canUseCompressed = false; 3694 canUseCompressed = false;
3671 3695 }
3672 if (!canUseImproved && !canUseCompressed) 3696
3697 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3698 {
3699 canUseCompressed = false;
3700 canUseImproved = false;
3701 }
3702 else
3703 {
3704 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3705 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3706 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3707 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3673 { 3708 {
3674 if (update.Entity is ScenePresence) 3709 canUseCompressed = false;
3675 {
3676 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3677 }
3678 else
3679 {
3680 // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3681 // {
3682 // SceneObjectPart sop = (SceneObjectPart)update.Entity;
3683 // string text = sop.Text;
3684 // if (text.IndexOf("\n") >= 0)
3685 // text = text.Remove(text.IndexOf("\n"));
3686 //
3687 // if (m_attachmentsSent.Contains(sop.ParentID))
3688 // {
3689 //// m_log.DebugFormat(
3690 //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3691 //// sop.LocalId, text);
3692 //
3693 // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3694 //
3695 // m_attachmentsSent.Add(sop.LocalId);
3696 // }
3697 // else
3698 // {
3699 // m_log.DebugFormat(
3700 // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3701 // sop.LocalId, text, sop.ParentID);
3702 //
3703 // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3704 // }
3705 // }
3706 // else
3707 // {
3708 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3709 // }
3710 }
3711 } 3710 }
3712 else if (!canUseImproved) 3711
3712 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3713 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3714 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3715 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3716 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3717 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3718 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3719 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3720 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3721 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3722 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3723 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3724 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3725 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3713 { 3726 {
3714 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3727 canUseImproved = false;
3728 }
3729 }
3730
3731 #endregion UpdateFlags to packet type conversion
3732
3733 #region Block Construction
3734
3735 // TODO: Remove this once we can build compressed updates
3736 canUseCompressed = false;
3737
3738 if (!canUseImproved && !canUseCompressed)
3739 {
3740 if (update.Entity is ScenePresence)
3741 {
3742 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3715 } 3743 }
3716 else 3744 else
3717 { 3745 {
3718 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3746// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3719 // Self updates go into a special list 3747// {
3720 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3748// SceneObjectPart sop = (SceneObjectPart)update.Entity;
3721 else 3749// string text = sop.Text;
3722 // Everything else goes here 3750// if (text.IndexOf("\n") >= 0)
3723 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3751// text = text.Remove(text.IndexOf("\n"));
3752//
3753// if (m_attachmentsSent.Contains(sop.ParentID))
3754// {
3755//// m_log.DebugFormat(
3756//// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3757//// sop.LocalId, text);
3758//
3759// objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3760//
3761// m_attachmentsSent.Add(sop.LocalId);
3762// }
3763// else
3764// {
3765// m_log.DebugFormat(
3766// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3767// sop.LocalId, text, sop.ParentID);
3768//
3769// m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3770// }
3771// }
3772// else
3773// {
3774 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3775// }
3724 } 3776 }
3725
3726 #endregion Block Construction
3727 } 3777 }
3778 else if (!canUseImproved)
3779 {
3780 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3781 }
3782 else
3783 {
3784 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3785 // Self updates go into a special list
3786 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3787 else
3788 // Everything else goes here
3789 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3790 }
3791
3792 #endregion Block Construction
3793 }
3794
3795 #region Packet Sending
3728 3796
3729 #region Packet Sending 3797 const float TIME_DILATION = 1.0f;
3730 3798 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3731 //const float TIME_DILATION = 1.0f; 3799
3800 if (terseAgentUpdateBlocks.IsValueCreated)
3801 {
3802 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3803
3804 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3805 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3806 packet.RegionData.TimeDilation = timeDilation;
3807 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3732 3808
3809 for (int i = 0; i < blocks.Count; i++)
3810 packet.ObjectData[i] = blocks[i];
3733 3811
3734 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3812 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3813 }
3814
3815 if (objectUpdateBlocks.IsValueCreated)
3816 {
3817 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3735 3818
3736 if (terseAgentUpdateBlocks.IsValueCreated) 3819 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3737 { 3820 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3738 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3821 packet.RegionData.TimeDilation = timeDilation;
3822 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3823
3824 for (int i = 0; i < blocks.Count; i++)
3825 packet.ObjectData[i] = blocks[i];
3739 3826
3740 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3827 OutPacket(packet, ThrottleOutPacketType.Task, true);
3741 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3828 }
3742 packet.RegionData.TimeDilation = timeDilation; 3829
3743 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3830 if (compressedUpdateBlocks.IsValueCreated)
3831 {
3832 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3744 3833
3745 for (int i = 0; i < blocks.Count; i++) 3834 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3746 packet.ObjectData[i] = blocks[i]; 3835 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3836 packet.RegionData.TimeDilation = timeDilation;
3837 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3747 3838
3748 3839 for (int i = 0; i < blocks.Count; i++)
3749 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3840 packet.ObjectData[i] = blocks[i];
3750 }
3751 3841
3752 if (objectUpdateBlocks.IsValueCreated) 3842 OutPacket(packet, ThrottleOutPacketType.Task, true);
3753 { 3843 }
3754 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3844
3755 3845 if (terseUpdateBlocks.IsValueCreated)
3756 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3846 {
3757 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3847 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3758 packet.RegionData.TimeDilation = timeDilation; 3848
3759 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3849 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3760 3850 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3761 for (int i = 0; i < blocks.Count; i++) 3851 packet.RegionData.TimeDilation = timeDilation;
3762 packet.ObjectData[i] = blocks[i]; 3852 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3763 3853
3764 OutPacket(packet, ThrottleOutPacketType.Task, true); 3854 for (int i = 0; i < blocks.Count; i++)
3765 } 3855 packet.ObjectData[i] = blocks[i];
3766 3856
3767 if (compressedUpdateBlocks.IsValueCreated) 3857 OutPacket(packet, ThrottleOutPacketType.Task, true);
3768 {
3769 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3770
3771 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3772 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3773 packet.RegionData.TimeDilation = timeDilation;
3774 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3775
3776 for (int i = 0; i < blocks.Count; i++)
3777 packet.ObjectData[i] = blocks[i];
3778
3779 OutPacket(packet, ThrottleOutPacketType.Task, true);
3780 }
3781
3782 if (terseUpdateBlocks.IsValueCreated)
3783 {
3784 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3785
3786 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3787 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3788 packet.RegionData.TimeDilation = timeDilation;
3789 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3790
3791 for (int i = 0; i < blocks.Count; i++)
3792 packet.ObjectData[i] = blocks[i];
3793
3794 OutPacket(packet, ThrottleOutPacketType.Task, true);
3795 }
3796 } 3858 }
3797 3859
3798 #endregion Packet Sending 3860 #endregion Packet Sending
@@ -4058,6 +4120,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4058 { 4120 {
4059 m_propertiesPacketTimer.Stop(); 4121 m_propertiesPacketTimer.Stop();
4060 4122
4123 if (m_propertiesBlocks.Count == 0)
4124 return;
4125
4061 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4126 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
4062 4127
4063 int index = 0; 4128 int index = 0;
@@ -4449,14 +4514,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4449 4514
4450 if (notifyCount > 0) 4515 if (notifyCount > 0)
4451 { 4516 {
4452 if (notifyCount > 32) 4517// if (notifyCount > 32)
4453 { 4518// {
4454 m_log.InfoFormat( 4519// m_log.InfoFormat(
4455 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4520// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4456 + " - a developer might want to investigate whether this is a hard limit", 32); 4521// + " - a developer might want to investigate whether this is a hard limit", 32);
4457 4522//
4458 notifyCount = 32; 4523// notifyCount = 32;
4459 } 4524// }
4460 4525
4461 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4526 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4462 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4527 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4964,6 +5029,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4964 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5029 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4965 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5030 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4966 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5031 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5032 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4967 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5033 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4968 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5034 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4969 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5035 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5063,6 +5129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5063 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5129 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5064 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5130 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5065 (x.ControlFlags != lastarg.ControlFlags) || 5131 (x.ControlFlags != lastarg.ControlFlags) ||
5132 (x.ControlFlags != 0) ||
5066 (x.Far != lastarg.Far) || 5133 (x.Far != lastarg.Far) ||
5067 (x.Flags != lastarg.Flags) || 5134 (x.Flags != lastarg.Flags) ||
5068 (x.State != lastarg.State) || 5135 (x.State != lastarg.State) ||
@@ -5436,7 +5503,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5436 args.Channel = ch; 5503 args.Channel = ch;
5437 args.From = String.Empty; 5504 args.From = String.Empty;
5438 args.Message = Utils.BytesToString(msg); 5505 args.Message = Utils.BytesToString(msg);
5439 args.Type = ChatTypeEnum.Shout; 5506 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5440 args.Position = new Vector3(); 5507 args.Position = new Vector3();
5441 args.Scene = Scene; 5508 args.Scene = Scene;
5442 args.Sender = this; 5509 args.Sender = this;
@@ -9408,7 +9475,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9408 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9475 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9409 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9476 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9410 UpdateMuteListEntry.MuteData.MuteType, 9477 UpdateMuteListEntry.MuteData.MuteType,
9411 UpdateMuteListEntry.AgentData.AgentID); 9478 UpdateMuteListEntry.MuteData.MuteFlags);
9412 return true; 9479 return true;
9413 } 9480 }
9414 return false; 9481 return false;
@@ -9423,8 +9490,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9423 { 9490 {
9424 handlerRemoveMuteListEntry(this, 9491 handlerRemoveMuteListEntry(this,
9425 RemoveMuteListEntry.MuteData.MuteID, 9492 RemoveMuteListEntry.MuteData.MuteID,
9426 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9493 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9427 RemoveMuteListEntry.AgentData.AgentID);
9428 return true; 9494 return true;
9429 } 9495 }
9430 return false; 9496 return false;
@@ -9472,6 +9538,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9472 { 9538 {
9473 return true; 9539 return true;
9474 } 9540 }
9541
9542 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9543 {
9544 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9545
9546 #region Packet Session and User Check
9547 if (m_checkPackets)
9548 {
9549 if (packet.AgentData.SessionID != SessionId ||
9550 packet.AgentData.AgentID != AgentId)
9551 return true;
9552 }
9553 #endregion
9554 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9555 List<InventoryItemBase> items = new List<InventoryItemBase>();
9556 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9557 {
9558 InventoryItemBase b = new InventoryItemBase();
9559 b.ID = n.OldItemID;
9560 b.Folder = n.OldFolderID;
9561 items.Add(b);
9562 }
9563
9564 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9565 if (handlerMoveItemsAndLeaveCopy != null)
9566 {
9567 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9568 }
9569
9570 return true;
9571 }
9475 9572
9476 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9573 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9477 { 9574 {
@@ -10470,11 +10567,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10470 10567
10471 StartLure handlerStartLure = OnStartLure; 10568 StartLure handlerStartLure = OnStartLure;
10472 if (handlerStartLure != null) 10569 if (handlerStartLure != null)
10473 handlerStartLure(startLureRequest.Info.LureType, 10570 {
10474 Utils.BytesToString( 10571 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10475 startLureRequest.Info.Message), 10572 {
10476 startLureRequest.TargetData[0].TargetID, 10573 handlerStartLure(startLureRequest.Info.LureType,
10477 this); 10574 Utils.BytesToString(
10575 startLureRequest.Info.Message),
10576 startLureRequest.TargetData[i].TargetID,
10577 this);
10578 }
10579 }
10478 return true; 10580 return true;
10479 } 10581 }
10480 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10582 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10969,7 +11071,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10969 { 11071 {
10970 // It's a ghost! tell the client to delete it from view. 11072 // It's a ghost! tell the client to delete it from view.
10971 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11073 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
10972 localId); 11074 new List<uint>() { localId });
10973 } 11075 }
10974 else 11076 else
10975 { 11077 {
@@ -11342,22 +11444,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11342 /// <param name="Pack">OpenMetaverse.packet</param> 11444 /// <param name="Pack">OpenMetaverse.packet</param>
11343 public void ProcessInPacket(Packet packet) 11445 public void ProcessInPacket(Packet packet)
11344 { 11446 {
11345 if (m_debugPacketLevel > 0) 11447 if (m_debugPacketLevel >= 255)
11346 { 11448 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11347 bool outputPacket = true;
11348
11349 if (m_debugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11350 outputPacket = false;
11351
11352 if (m_debugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11353 outputPacket = false;
11354
11355 if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11356 outputPacket = false;
11357
11358 if (outputPacket)
11359 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11360 }
11361 11449
11362 if (!ProcessPacketMethod(packet)) 11450 if (!ProcessPacketMethod(packet))
11363 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11451 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
@@ -11599,7 +11687,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11599 11687
11600// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11688// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11601 11689
11690
11691 //Note, the bool returned from the below function is useless since it is always false.
11602 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11692 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11693
11603 } 11694 }
11604 11695
11605 /// <summary> 11696 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index e02783a..5aa9b40 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -149,6 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 149
150 private int m_defaultRTO = 3000; 150 private int m_defaultRTO = 3000;
151 private int m_maxRTO = 60000; 151 private int m_maxRTO = 60000;
152 public bool m_deliverPackets = true;
152 153
153 /// <summary> 154 /// <summary>
154 /// Default constructor 155 /// Default constructor
@@ -415,6 +416,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
415 if (category >= 0 && category < m_packetOutboxes.Length) 416 if (category >= 0 && category < m_packetOutboxes.Length)
416 { 417 {
417 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 418 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
419
420 if (m_deliverPackets == false)
421 {
422 queue.Enqueue(packet);
423 return true;
424 }
425
418 TokenBucket bucket = m_throttleCategories[category]; 426 TokenBucket bucket = m_throttleCategories[category];
419 427
420 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) 428 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
@@ -451,6 +459,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
451 /// <returns>True if any packets were sent, otherwise false</returns> 459 /// <returns>True if any packets were sent, otherwise false</returns>
452 public bool DequeueOutgoing() 460 public bool DequeueOutgoing()
453 { 461 {
462 if (m_deliverPackets == false) return false;
463
454 OutgoingPacket packet; 464 OutgoingPacket packet;
455 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 465 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
456 TokenBucket bucket; 466 TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index e54cfc2..6985449 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -952,7 +952,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
952 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 952 if (m_scene.TryGetClient(udpClient.AgentID, out client))
953 { 953 {
954 client.IsLoggingOut = true; 954 client.IsLoggingOut = true;
955 client.Close(); 955 client.Close(false);
956 } 956 }
957 } 957 }
958 958
@@ -964,6 +964,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
964 964
965 while (base.IsRunning) 965 while (base.IsRunning)
966 { 966 {
967 m_scene.ThreadAlive(1);
967 try 968 try
968 { 969 {
969 IncomingPacket incomingPacket = null; 970 IncomingPacket incomingPacket = null;
@@ -1006,6 +1007,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1006 1007
1007 while (base.IsRunning) 1008 while (base.IsRunning)
1008 { 1009 {
1010 m_scene.ThreadAlive(2);
1009 try 1011 try
1010 { 1012 {
1011 m_packetSent = false; 1013 m_packetSent = false;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index bdbd284..91e3d20 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
133 this.parent = parent; 133 this.parent = parent;
134 MaxBurst = maxBurst; 134 MaxBurst = maxBurst;
135 DripRate = dripRate; 135 DripRate = dripRate;
136 lastDrip = Environment.TickCount & Int32.MaxValue; 136 lastDrip = Environment.TickCount;
137 } 137 }
138 138
139 /// <summary> 139 /// <summary>
@@ -144,40 +144,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 /// the bucket, otherwise false</returns> 144 /// the bucket, otherwise false</returns>
145 public bool RemoveTokens(int amount) 145 public bool RemoveTokens(int amount)
146 { 146 {
147 bool dummy;
148 return RemoveTokens(amount, out dummy);
149 }
150
151 /// <summary>
152 /// Remove a given number of tokens from the bucket
153 /// </summary>
154 /// <param name="amount">Number of tokens to remove from the bucket</param>
155 /// <param name="dripSucceeded">True if tokens were added to the bucket
156 /// during this call, otherwise false</param>
157 /// <returns>True if the requested number of tokens were removed from
158 /// the bucket, otherwise false</returns>
159 public bool RemoveTokens(int amount, out bool dripSucceeded)
160 {
161 if (maxBurst == 0) 147 if (maxBurst == 0)
162 { 148 {
163 dripSucceeded = true;
164 return true; 149 return true;
165 } 150 }
166 151
167 dripSucceeded = Drip(); 152 if (amount > maxBurst)
168
169 if (content - amount >= 0)
170 { 153 {
171 if (parent != null && !parent.RemoveTokens(amount)) 154 throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst);
172 return false; 155 }
173 156
174 content -= amount; 157 Drip();
175 return true; 158
159 if (content < amount)
160 {
161 return false;
176 } 162 }
177 else 163
164 if (parent != null && !parent.RemoveTokens(amount))
178 { 165 {
179 return false; 166 return false;
180 } 167 }
168
169 content -= amount;
170 return true;
181 } 171 }
182 172
183 /// <summary> 173 /// <summary>
@@ -193,25 +183,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 content = maxBurst; 183 content = maxBurst;
194 return true; 184 return true;
195 } 185 }
196 else
197 {
198 int now = Environment.TickCount & Int32.MaxValue;
199 int deltaMS = now - lastDrip;
200 186
201 if (deltaMS <= 0) 187 int now = Environment.TickCount;
202 { 188 int deltaMS = now - lastDrip;
203 if (deltaMS < 0) 189 lastDrip = now;
204 lastDrip = now;
205 return false;
206 }
207 190
208 int dripAmount = deltaMS * tokensPerMS; 191 if (deltaMS <= 0)
209 192 {
210 content = Math.Min(content + dripAmount, maxBurst); 193 return false;
211 lastDrip = now; 194 }
212 195
213 return true; 196 long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
197 if (dripAmount > maxBurst)
198 {
199 dripAmount = maxBurst;
214 } 200 }
201 content = (int)dripAmount;
202 return true;
215 } 203 }
216 } 204 }
217} 205}
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
index c66a4ea..d7f3f2c 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -167,6 +167,19 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
167 { 167 {
168 if (XferUploaders.ContainsKey(transactionID)) 168 if (XferUploaders.ContainsKey(transactionID))
169 { 169 {
170 m_log.DebugFormat("[XFER]: Asked to update item {0} ({1})",
171 item.Name, item.ID);
172
173 // Here we need to get the old asset to extract the
174 // texture UUIDs if it's a wearable.
175 if (item.AssetType == (int)AssetType.Bodypart ||
176 item.AssetType == (int)AssetType.Clothing)
177 {
178 AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
179 if (oldAsset != null)
180 XferUploaders[transactionID].SetOldData(oldAsset.Data);
181 }
182
170 AssetBase asset = GetTransactionAsset(transactionID); 183 AssetBase asset = GetTransactionAsset(transactionID);
171 184
172 if (asset != null) 185 if (asset != null)
@@ -181,6 +194,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
181 194
182 IInventoryService invService = m_Scene.InventoryService; 195 IInventoryService invService = m_Scene.InventoryService;
183 invService.UpdateItem(item); 196 invService.UpdateItem(item);
197
198 m_log.DebugFormat("[XFER]: Updated item {0} ({1}) with asset {2}",
199 item.Name, item.ID, asset.FullID);
184 } 200 }
185 } 201 }
186 } 202 }
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index a7929ba..a5dcdcc 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Collections.Generic;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
33using OpenSim.Framework; 34using OpenSim.Framework;
@@ -38,6 +39,13 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
38{ 39{
39 public class AssetXferUploader 40 public class AssetXferUploader
40 { 41 {
42 // Viewer's notion of the default texture
43 private List<UUID> defaultIDs = new List<UUID> {
44 new UUID("5748decc-f629-461c-9a36-a35a221fe21f"),
45 new UUID("7ca39b4c-bd19-4699-aff7-f93fd03d3e7b"),
46 new UUID("6522e74d-1660-4e7f-b601-6f48c1659a77"),
47 new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97")
48 };
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 50
43 private AssetBase m_asset; 51 private AssetBase m_asset;
@@ -55,6 +63,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
55 private UUID TransactionID = UUID.Zero; 63 private UUID TransactionID = UUID.Zero;
56 private sbyte type = 0; 64 private sbyte type = 0;
57 private byte wearableType = 0; 65 private byte wearableType = 0;
66 private byte[] m_oldData = null;
58 public ulong XferID; 67 public ulong XferID;
59 private Scene m_Scene; 68 private Scene m_Scene;
60 69
@@ -219,6 +228,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
219 228
220 private void DoCreateItem(uint callbackID) 229 private void DoCreateItem(uint callbackID)
221 { 230 {
231 ValidateAssets();
222 m_Scene.AssetService.Store(m_asset); 232 m_Scene.AssetService.Store(m_asset);
223 233
224 InventoryItemBase item = new InventoryItemBase(); 234 InventoryItemBase item = new InventoryItemBase();
@@ -239,12 +249,84 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
239 item.Flags = (uint) wearableType; 249 item.Flags = (uint) wearableType;
240 item.CreationDate = Util.UnixTimeSinceEpoch(); 250 item.CreationDate = Util.UnixTimeSinceEpoch();
241 251
252 m_log.DebugFormat("[XFER]: Created item {0} with asset {1}",
253 item.ID, item.AssetID);
254
242 if (m_Scene.AddInventoryItem(item)) 255 if (m_Scene.AddInventoryItem(item))
243 ourClient.SendInventoryItemCreateUpdate(item, callbackID); 256 ourClient.SendInventoryItemCreateUpdate(item, callbackID);
244 else 257 else
245 ourClient.SendAlertMessage("Unable to create inventory item"); 258 ourClient.SendAlertMessage("Unable to create inventory item");
246 } 259 }
247 260
261 private void ValidateAssets()
262 {
263 if (m_asset.Type == (sbyte)AssetType.Clothing ||
264 m_asset.Type == (sbyte)AssetType.Bodypart)
265 {
266 string content = System.Text.Encoding.ASCII.GetString(m_asset.Data);
267 string[] lines = content.Split(new char[] {'\n'});
268
269 List<string> validated = new List<string>();
270
271 Dictionary<int, UUID> allowed = ExtractTexturesFromOldData();
272
273 int textures = 0;
274
275 foreach (string line in lines)
276 {
277 try
278 {
279 if (line.StartsWith("textures "))
280 {
281 textures = Convert.ToInt32(line.Substring(9));
282 validated.Add(line);
283 }
284 else if (textures > 0)
285 {
286 string[] parts = line.Split(new char[] {' '});
287
288 UUID tx = new UUID(parts[1]);
289 int id = Convert.ToInt32(parts[0]);
290
291 if (defaultIDs.Contains(tx) || tx == UUID.Zero ||
292 (allowed.ContainsKey(id) && allowed[id] == tx))
293 {
294 validated.Add(parts[0] + " " + tx.ToString());
295 }
296 else
297 {
298 int perms = m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, tx);
299 int full = (int)(PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Copy);
300
301 if ((perms & full) != full)
302 {
303 m_log.ErrorFormat("[ASSET UPLOADER]: REJECTED update with texture {0} from {1} because they do not own the texture", tx, ourClient.AgentId);
304 validated.Add(parts[0] + " " + UUID.Zero.ToString());
305 }
306 else
307 {
308 validated.Add(line);
309 }
310 }
311 textures--;
312 }
313 else
314 {
315 validated.Add(line);
316 }
317 }
318 catch
319 {
320 // If it's malformed, skip it
321 }
322 }
323
324 string final = String.Join("\n", validated.ToArray());
325
326 m_asset.Data = System.Text.Encoding.ASCII.GetBytes(final);
327 }
328 }
329
248 /// <summary> 330 /// <summary>
249 /// Get the asset data uploaded in this transfer. 331 /// Get the asset data uploaded in this transfer.
250 /// </summary> 332 /// </summary>
@@ -253,10 +335,55 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
253 { 335 {
254 if (m_finished) 336 if (m_finished)
255 { 337 {
338 ValidateAssets();
256 return m_asset; 339 return m_asset;
257 } 340 }
258 341
259 return null; 342 return null;
260 } 343 }
344
345 public void SetOldData(byte[] d)
346 {
347 m_oldData = d;
348 }
349
350 private Dictionary<int,UUID> ExtractTexturesFromOldData()
351 {
352 Dictionary<int,UUID> result = new Dictionary<int,UUID>();
353 if (m_oldData == null)
354 return result;
355
356 string content = System.Text.Encoding.ASCII.GetString(m_oldData);
357 string[] lines = content.Split(new char[] {'\n'});
358
359 int textures = 0;
360
361 foreach (string line in lines)
362 {
363 try
364 {
365 if (line.StartsWith("textures "))
366 {
367 textures = Convert.ToInt32(line.Substring(9));
368 }
369 else if (textures > 0)
370 {
371 string[] parts = line.Split(new char[] {' '});
372
373 UUID tx = new UUID(parts[1]);
374 int id = Convert.ToInt32(parts[0]);
375 result[id] = tx;
376 textures--;
377 }
378 }
379 catch
380 {
381 // If it's malformed, skip it
382 }
383 }
384
385 return result;
386 }
261 } 387 }
262} 388}
389
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 6ed4867..e542d7d 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -271,7 +271,16 @@ namespace Flotsam.RegionModules.AssetCache
271 // If the file is already cached, don't cache it, just touch it so access time is updated 271 // If the file is already cached, don't cache it, just touch it so access time is updated
272 if (File.Exists(filename)) 272 if (File.Exists(filename))
273 { 273 {
274 File.SetLastAccessTime(filename, DateTime.Now); 274 // We don't really want to know about sharing
275 // violations here. If the file is locked, then
276 // the other thread has updated the time for us.
277 try
278 {
279 File.SetLastAccessTime(filename, DateTime.Now);
280 }
281 catch
282 {
283 }
275 } else { 284 } else {
276 285
277 // Once we start writing, make sure we flag that we're writing 286 // Once we start writing, make sure we flag that we're writing
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 360a014..25d4f21 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;
@@ -228,15 +229,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
228 public UUID RezSingleAttachmentFromInventory( 229 public UUID RezSingleAttachmentFromInventory(
229 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) 230 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
230 { 231 {
231 m_log.DebugFormat( 232 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null);
232 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 233 }
233 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 234
234 235 public UUID RezSingleAttachmentFromInventory(
236 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
237 {
235 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 238 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
236 // be removed when that functionality is implemented in opensim 239 // be removed when that functionality is implemented in opensim
237 AttachmentPt &= 0x7f; 240 AttachmentPt &= 0x7f;
238 241
239 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); 242 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt, doc);
240 243
241 if (updateInventoryStatus) 244 if (updateInventoryStatus)
242 { 245 {
@@ -253,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
253 } 256 }
254 257
255 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 258 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
256 IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 259 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, XmlDocument doc)
257 { 260 {
258 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 261 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
259 if (invAccess != null) 262 if (invAccess != null)
@@ -291,13 +294,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
291 if (tainted) 294 if (tainted)
292 objatt.HasGroupChanged = true; 295 objatt.HasGroupChanged = true;
293 296
297 if (doc != null)
298 {
299 objatt.LoadScriptState(doc);
300 objatt.ResetOwnerChangeFlag();
301 }
302
294 // Fire after attach, so we don't get messy perms dialogs 303 // Fire after attach, so we don't get messy perms dialogs
295 // 4 == AttachedRez 304 // 4 == AttachedRez
296 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 305 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
297 objatt.ResumeScripts(); 306 objatt.ResumeScripts();
298 307
299 // Do this last so that event listeners have access to all the effects of the attachment 308 // Do this last so that event listeners have access to all the effects of the attachment
300 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); 309 //m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
301 } 310 }
302 else 311 else
303 { 312 {
@@ -334,9 +343,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
334 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 343 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
335 { 344 {
336 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 345 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
337 item = m_scene.InventoryService.GetItem(item); 346 if (m_scene.InventoryService != null)
347 item = m_scene.InventoryService.GetItem(item);
338 348
339 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/); 349 if (presence.Appearance != null)
350 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/);
340 } 351 }
341 352
342 return att.UUID; 353 return att.UUID;
@@ -379,6 +390,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
379 { 390 {
380 // XXYY!! 391 // XXYY!!
381 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 392 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
393 if (item == null)
394 m_log.Error("[ATTACHMENT]: item == null");
395 if (m_scene == null)
396 m_log.Error("[ATTACHMENT]: m_scene == null");
397 if (m_scene.InventoryService == null)
398 m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null");
382 item = m_scene.InventoryService.GetItem(item); 399 item = m_scene.InventoryService.GetItem(item);
383 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */); 400 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */);
384 401
@@ -467,6 +484,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
467 if (group.GetFromItemID() == itemID) 484 if (group.GetFromItemID() == itemID)
468 { 485 {
469 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); 486 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
487 // CM / XMREngine!!!! Needed to conclude attach event
488 //SceneObjectSerializer.ToOriginalXmlFormat(group);
470 group.DetachToInventoryPrep(); 489 group.DetachToInventoryPrep();
471 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 490 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
472 491
@@ -484,22 +503,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
484 } 503 }
485 } 504 }
486 505
487 public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos)
488 {
489 // First we save the
490 // attachment point information, then we update the relative
491 // positioning. Then we have to mark the object as NOT an
492 // attachment. This is necessary in order to correctly save
493 // and retrieve GroupPosition information for the attachment.
494 // Finally, we restore the object's attachment status.
495 byte attachmentPoint = sog.GetAttachmentPoint();
496 sog.UpdateGroupPosition(pos);
497 sog.RootPart.IsAttachment = false;
498 sog.AbsolutePosition = sog.RootPart.AttachedPos;
499 sog.SetAttachmentPoint(attachmentPoint);
500 sog.HasGroupChanged = true;
501 }
502
503 /// <summary> 506 /// <summary>
504 /// Update the attachment asset for the new sog details if they have changed. 507 /// Update the attachment asset for the new sog details if they have changed.
505 /// </summary> 508 /// </summary>
@@ -603,15 +606,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
603 606
604 if (!silent) 607 if (!silent)
605 { 608 {
606 // Killing it here will cause the client to deselect it
607 // It then reappears on the avatar, deselected
608 // through the full update below
609 //
610 if (so.IsSelected)
611 {
612 m_scene.SendKillObject(so.RootPart.LocalId);
613 }
614
615 so.IsSelected = false; // fudge.... 609 so.IsSelected = false; // fudge....
616 so.ScheduleGroupForFullUpdate(); 610 so.ScheduleGroupForFullUpdate();
617 } 611 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 4359c01..35a3f43 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -49,7 +49,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
49 private int m_shoutdistance = 100; 49 private int m_shoutdistance = 100;
50 private int m_whisperdistance = 10; 50 private int m_whisperdistance = 10;
51 private List<Scene> m_scenes = new List<Scene>(); 51 private List<Scene> m_scenes = new List<Scene>();
52 52 private List<string> FreezeCache = new List<string>();
53 private string m_adminPrefix = "";
53 internal object m_syncy = new object(); 54 internal object m_syncy = new object();
54 55
55 internal IConfig m_config; 56 internal IConfig m_config;
@@ -76,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
76 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); 77 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
77 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); 78 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
78 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); 79 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
80 m_adminPrefix = config.Configs["Chat"].GetString("admin_prefix", "");
79 } 81 }
80 82
81 public virtual void AddRegion(Scene scene) 83 public virtual void AddRegion(Scene scene)
@@ -171,7 +173,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
171 return; 173 return;
172 } 174 }
173 175
174 DeliverChatToAvatars(ChatSourceType.Agent, c); 176 if (FreezeCache.Contains(c.Sender.AgentId.ToString()))
177 {
178 if (c.Type != ChatTypeEnum.StartTyping || c.Type != ChatTypeEnum.StopTyping)
179 c.Sender.SendAgentAlertMessage("You may not talk as you are frozen.", false);
180 }
181 else
182 {
183 DeliverChatToAvatars(ChatSourceType.Agent, c);
184 }
175 } 185 }
176 186
177 public virtual void OnChatFromWorld(Object sender, OSChatMessage c) 187 public virtual void OnChatFromWorld(Object sender, OSChatMessage c)
@@ -185,6 +195,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
185 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) 195 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c)
186 { 196 {
187 string fromName = c.From; 197 string fromName = c.From;
198 string fromNamePrefix = "";
188 UUID fromID = UUID.Zero; 199 UUID fromID = UUID.Zero;
189 string message = c.Message; 200 string message = c.Message;
190 IScene scene = c.Scene; 201 IScene scene = c.Scene;
@@ -207,7 +218,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
207 fromPos = avatar.AbsolutePosition; 218 fromPos = avatar.AbsolutePosition;
208 fromName = avatar.Name; 219 fromName = avatar.Name;
209 fromID = c.Sender.AgentId; 220 fromID = c.Sender.AgentId;
210 221 if (avatar.GodLevel >= 200)
222 {
223 fromNamePrefix = m_adminPrefix;
224 }
211 break; 225 break;
212 226
213 case ChatSourceType.Object: 227 case ChatSourceType.Object:
@@ -231,8 +245,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
231 s.ForEachScenePresence( 245 s.ForEachScenePresence(
232 delegate(ScenePresence presence) 246 delegate(ScenePresence presence)
233 { 247 {
234 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType)) 248 ILandObject Presencecheck = s.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
235 receiverIDs.Add(presence.UUID); 249 if (Presencecheck != null)
250 {
251 // This will pass all chat from objects. Not
252 // perfect, but it will do. For now. Better
253 // than the prior behavior of muting all
254 // objects on a parcel with access restrictions
255 if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true)
256 {
257 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix + fromName, c.Type, message, sourceType))
258 receiverIDs.Add(presence.UUID);
259 }
260 }
261
236 } 262 }
237 ); 263 );
238 } 264 }
@@ -276,31 +302,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
276 } 302 }
277 303
278 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 304 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
279
280 HashSet<UUID> receiverIDs = new HashSet<UUID>(); 305 HashSet<UUID> receiverIDs = new HashSet<UUID>();
281 306
282 ((Scene)c.Scene).ForEachScenePresence( 307 if (c.Scene != null)
283 delegate(ScenePresence presence) 308 {
284 { 309 ((Scene)c.Scene).ForEachScenePresence
285 // ignore chat from child agents 310 (
286 if (presence.IsChildAgent) return; 311 delegate(ScenePresence presence)
287 312 {
288 IClientAPI client = presence.ControllingClient; 313 // ignore chat from child agents
289 314 if (presence.IsChildAgent) return;
290 // don't forward SayOwner chat from objects to 315
291 // non-owner agents 316 IClientAPI client = presence.ControllingClient;
292 if ((c.Type == ChatTypeEnum.Owner) && 317
293 (null != c.SenderObject) && 318 // don't forward SayOwner chat from objects to
294 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) 319 // non-owner agents
295 return; 320 if ((c.Type == ChatTypeEnum.Owner) &&
296 321 (null != c.SenderObject) &&
297 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, 322 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
298 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 323 return;
299 receiverIDs.Add(presence.UUID); 324
300 }); 325 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
301 326 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
302 (c.Scene as Scene).EventManager.TriggerOnChatToClients( 327 receiverIDs.Add(presence.UUID);
303 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); 328 }
329 );
330 (c.Scene as Scene).EventManager.TriggerOnChatToClients(
331 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully);
332 }
304 } 333 }
305 334
306 /// <summary> 335 /// <summary>
@@ -343,5 +372,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
343 372
344 return true; 373 return true;
345 } 374 }
375
376 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
377 public void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
378 {
379 System.Threading.Timer Timer;
380 if (flags == 0)
381 {
382 FreezeCache.Add(target.ToString());
383 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
384 Timer = new System.Threading.Timer(timeCB, target, 30000, 0);
385 Timers.Add(target, Timer);
386 }
387 else
388 {
389 FreezeCache.Remove(target.ToString());
390 Timers.TryGetValue(target, out Timer);
391 Timers.Remove(target);
392 Timer.Dispose();
393 }
394 }
395
396 private void OnEndParcelFrozen(object avatar)
397 {
398 UUID target = (UUID)avatar;
399 FreezeCache.Remove(target.ToString());
400 System.Threading.Timer Timer;
401 Timers.TryGetValue(target, out Timer);
402 Timers.Remove(target);
403 Timer.Dispose();
404 }
346 } 405 }
347} 406}
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index 2b3d2a9..a514a83 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -239,4 +239,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
239 return result; 239 return result;
240 } 240 }
241 } 241 }
242} \ No newline at end of file 242}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 4d74b2a..3148871 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -273,7 +273,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
273 273
274 // Inform the friends that this user is online 274 // Inform the friends that this user is online
275 StatusChange(agentID, true); 275 StatusChange(agentID, true);
276 276
277 // Register that we need to send the list of online friends to this user 277 // Register that we need to send the list of online friends to this user
278 lock (m_NeedsListOfFriends) 278 lock (m_NeedsListOfFriends)
279 m_NeedsListOfFriends.Add(agentID); 279 m_NeedsListOfFriends.Add(agentID);
@@ -516,6 +516,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
516 FriendsService.StoreFriend(agentID, friendID.ToString(), 1); 516 FriendsService.StoreFriend(agentID, friendID.ToString(), 1);
517 FriendsService.StoreFriend(friendID, agentID.ToString(), 1); 517 FriendsService.StoreFriend(friendID, agentID.ToString(), 1);
518 518
519 ICallingCardModule ccm = client.Scene.RequestModuleInterface<ICallingCardModule>();
520 if (ccm != null)
521 {
522 ccm.CreateCallingCard(agentID, friendID, UUID.Zero);
523 }
524
519 // Update the local cache 525 // Update the local cache
520 UpdateFriendsCache(agentID); 526 UpdateFriendsCache(agentID);
521 527
@@ -679,6 +685,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
679 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero); 685 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero);
680 friendClient.SendInstantMessage(im); 686 friendClient.SendInstantMessage(im);
681 687
688 ICallingCardModule ccm = friendClient.Scene.RequestModuleInterface<ICallingCardModule>();
689 if (ccm != null)
690 {
691 ccm.CreateCallingCard(friendID, userID, UUID.Zero);
692 }
693
694
682 // Update the local cache 695 // Update the local cache
683 UpdateFriendsCache(friendID); 696 UpdateFriendsCache(friendID);
684 697
@@ -701,7 +714,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
701 // we're done 714 // we're done
702 return true; 715 return true;
703 } 716 }
704 717
705 return false; 718 return false;
706 } 719 }
707 720
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
index af39565..feb5fb8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -156,6 +156,32 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
156 return; 156 return;
157 } 157 }
158 158
159 //DateTime dt = DateTime.UtcNow;
160
161 // Ticks from UtcNow, but make it look like local. Evil, huh?
162 //dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
163
164 //try
165 //{
166 // // Convert that to the PST timezone
167 // TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
168 // dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
169 //}
170 //catch
171 //{
172 // //m_log.Info("[OFFLINE MESSAGING]: No PST timezone found on this machine. Saving with local timestamp.");
173 //}
174
175 //// And make it look local again to fool the unix time util
176 //dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
177
178 // If client is null, this message comes from storage and IS offline
179 if (client != null)
180 im.offline = 0;
181
182 if (im.offline == 0)
183 im.timestamp = (uint)Util.UnixTimeSinceEpoch();
184
159 if (m_TransferModule != null) 185 if (m_TransferModule != null)
160 { 186 {
161 if (client != null) 187 if (client != null)
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 21a61a7..0d5401b 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -47,6 +47,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private bool m_Enabled = false; 49 private bool m_Enabled = false;
50 protected string m_MessageKey = String.Empty;
50 protected List<Scene> m_Scenes = new List<Scene>(); 51 protected List<Scene> m_Scenes = new List<Scene>();
51 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); 52 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>();
52 53
@@ -66,14 +67,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
66 public virtual void Initialise(IConfigSource config) 67 public virtual void Initialise(IConfigSource config)
67 { 68 {
68 IConfig cnf = config.Configs["Messaging"]; 69 IConfig cnf = config.Configs["Messaging"];
69 if (cnf != null && cnf.GetString( 70 if (cnf != null)
70 "MessageTransferModule", "MessageTransferModule") !=
71 "MessageTransferModule")
72 { 71 {
73 m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); 72 if (cnf.GetString("MessageTransferModule",
74 return; 73 "MessageTransferModule") != "MessageTransferModule")
75 } 74 {
75 return;
76 }
76 77
78 m_MessageKey = cnf.GetString("MessageKey", String.Empty);
79 }
80 m_log.Debug("[MESSAGE TRANSFER]: Module enabled");
77 m_Enabled = true; 81 m_Enabled = true;
78 } 82 }
79 83
@@ -145,8 +149,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
145 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 149 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
146 if (!user.IsChildAgent) 150 if (!user.IsChildAgent)
147 { 151 {
148 // Local message 152 // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
149 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID);
150 user.ControllingClient.SendInstantMessage(im); 153 user.ControllingClient.SendInstantMessage(im);
151 154
152 // Message sent 155 // Message sent
@@ -168,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
168 // Local message 171 // Local message
169 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 172 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
170 173
171 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); 174 // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
172 user.ControllingClient.SendInstantMessage(im); 175 user.ControllingClient.SendInstantMessage(im);
173 176
174 // Message sent 177 // Message sent
@@ -251,6 +254,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
251 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") 254 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
252 && requestData.ContainsKey("binary_bucket")) 255 && requestData.ContainsKey("binary_bucket"))
253 { 256 {
257 if (m_MessageKey != String.Empty)
258 {
259 XmlRpcResponse error_resp = new XmlRpcResponse();
260 Hashtable error_respdata = new Hashtable();
261 error_respdata["success"] = "FALSE";
262 error_resp.Value = error_respdata;
263
264 if (!requestData.Contains("message_key"))
265 return error_resp;
266 if (m_MessageKey != (string)requestData["message_key"])
267 return error_resp;
268 }
269
254 // Do the easy way of validating the UUIDs 270 // Do the easy way of validating the UUIDs
255 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); 271 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
256 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); 272 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
@@ -533,7 +549,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
533 549
534 if (upd != null) 550 if (upd != null)
535 { 551 {
536 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, 552 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero,
537 upd.RegionID); 553 upd.RegionID);
538 if (reginfo != null) 554 if (reginfo != null)
539 { 555 {
@@ -682,6 +698,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
682 gim["position_z"] = msg.Position.Z.ToString(); 698 gim["position_z"] = msg.Position.Z.ToString();
683 gim["region_id"] = msg.RegionID.ToString(); 699 gim["region_id"] = msg.RegionID.ToString();
684 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 700 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
701 if (m_MessageKey != String.Empty)
702 gim["message_key"] = m_MessageKey;
685 return gim; 703 return gim;
686 } 704 }
687 705
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index fdfcd10..164ae50 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -172,13 +172,16 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
172 172
173 private void RetrieveInstantMessages(IClientAPI client) 173 private void RetrieveInstantMessages(IClientAPI client)
174 { 174 {
175 if (m_RestURL != "") 175 if (m_RestURL == String.Empty)
176 { 176 return;
177 m_log.DebugFormat("[OFFLINE MESSAGING] Retrieving stored messages for {0}", client.AgentId);
178 177
179 List<GridInstantMessage> msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>( 178 m_log.DebugFormat("[OFFLINE MESSAGING] Retrieving stored messages for {0}", client.AgentId);
179
180 List<GridInstantMessage> msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>(
180 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); 181 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
181 182
183 if (msglist != null)
184 {
182 foreach (GridInstantMessage im in msglist) 185 foreach (GridInstantMessage im in msglist)
183 { 186 {
184 // client.SendInstantMessage(im); 187 // client.SendInstantMessage(im);
@@ -189,6 +192,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
189 // Needed for proper state management for stored group 192 // Needed for proper state management for stored group
190 // invitations 193 // invitations
191 // 194 //
195
196 im.offline = 1;
197
192 Scene s = FindScene(client.AgentId); 198 Scene s = FindScene(client.AgentId);
193 if (s != null) 199 if (s != null)
194 s.EventManager.TriggerIncomingInstantMessage(im); 200 s.EventManager.TriggerIncomingInstantMessage(im);
@@ -198,26 +204,38 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
198 204
199 private void UndeliveredMessage(GridInstantMessage im) 205 private void UndeliveredMessage(GridInstantMessage im)
200 { 206 {
201 if ((im.offline != 0) 207 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
202 && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) 208 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
209 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
210 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
211 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
203 { 212 {
204 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>( 213 return;
205 "POST", m_RestURL+"/SaveMessage/", im); 214 }
206 215
207 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 216 // It's not delivered. Make sure the scope id is saved
208 { 217 // We don't need the imSessionID here anymore, overwrite it
209 IClientAPI client = FindClient(new UUID(im.fromAgentID)); 218 Scene scene = FindScene(new UUID(im.fromAgentID));
210 if (client == null) 219 if (scene == null)
211 return; 220 scene = m_SceneList[0];
212 221
213 client.SendInstantMessage(new GridInstantMessage( 222 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>(
214 null, new UUID(im.toAgentID), 223 "POST", m_RestURL+"/SaveMessage/?scope=" +
215 "System", new UUID(im.fromAgentID), 224 scene.RegionInfo.ScopeID.ToString(), im);
216 (byte)InstantMessageDialog.MessageFromAgent, 225
217 "User is not logged in. "+ 226 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
218 (success ? "Message saved." : "Message not saved"), 227 {
219 false, new Vector3())); 228 IClientAPI client = FindClient(new UUID(im.fromAgentID));
220 } 229 if (client == null)
230 return;
231
232 client.SendInstantMessage(new GridInstantMessage(
233 null, new UUID(im.toAgentID),
234 "System", new UUID(im.fromAgentID),
235 (byte)InstantMessageDialog.MessageFromAgent,
236 "User is not logged in. "+
237 (success ? "Message saved." : "Message not saved"),
238 false, new Vector3()));
221 } 239 }
222 } 240 }
223 } 241 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index e3d4969..528bc8d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -175,8 +175,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
175 if (im.binaryBucket.Length < 17) // Invalid 175 if (im.binaryBucket.Length < 17) // Invalid
176 return; 176 return;
177 177
178 UUID receipientID = new UUID(im.toAgentID); 178 UUID recipientID = new UUID(im.toAgentID);
179 ScenePresence user = scene.GetScenePresence(receipientID); 179 ScenePresence user = scene.GetScenePresence(recipientID);
180 UUID copyID; 180 UUID copyID;
181 181
182 // First byte is the asset type 182 // First byte is the asset type
@@ -191,7 +191,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
191 folderID, new UUID(im.toAgentID)); 191 folderID, new UUID(im.toAgentID));
192 192
193 InventoryFolderBase folderCopy 193 InventoryFolderBase folderCopy
194 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); 194 = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero);
195 195
196 if (folderCopy == null) 196 if (folderCopy == null)
197 { 197 {
@@ -248,6 +248,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
248 im.imSessionID = itemID.Guid; 248 im.imSessionID = itemID.Guid;
249 } 249 }
250 250
251 im.offline = 1; // Remember these
252
251 // Send the IM to the recipient. The item is already 253 // Send the IM to the recipient. The item is already
252 // in their inventory, so it will not be lost if 254 // in their inventory, so it will not be lost if
253 // they are offline. 255 // they are offline.
@@ -417,22 +419,67 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
417 /// 419 ///
418 /// </summary> 420 /// </summary>
419 /// <param name="msg"></param> 421 /// <param name="msg"></param>
420 private void OnGridInstantMessage(GridInstantMessage msg) 422 private void OnGridInstantMessage(GridInstantMessage im)
421 { 423 {
422 // Check if this is ours to handle 424 // Check if this is ours to handle
423 // 425 //
424 Scene scene = FindClientScene(new UUID(msg.toAgentID)); 426 Scene scene = FindClientScene(new UUID(im.toAgentID));
425 427
426 if (scene == null) 428 if (scene == null)
427 return; 429 return;
428 430
429 // Find agent to deliver to 431 // Find agent to deliver to
430 // 432 //
431 ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); 433 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
434 if (user == null)
435 return;
436
437 // This requires a little bit of processing because we have to make the
438 // new item visible in the recipient's inventory here
439 //
440 if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
441 {
442 if (im.binaryBucket.Length < 17) // Invalid
443 return;
444
445 UUID recipientID = new UUID(im.toAgentID);
446
447 // First byte is the asset type
448 AssetType assetType = (AssetType)im.binaryBucket[0];
449
450 if (AssetType.Folder == assetType)
451 {
452 UUID folderID = new UUID(im.binaryBucket, 1);
453
454 InventoryFolderBase given =
455 new InventoryFolderBase(folderID, recipientID);
456 InventoryFolderBase folder =
457 scene.InventoryService.GetFolder(given);
458
459 if (folder != null)
460 user.ControllingClient.SendBulkUpdateInventory(folder);
461 }
462 else
463 {
464 UUID itemID = new UUID(im.binaryBucket, 1);
432 465
433 // Just forward to local handling 466 InventoryItemBase given =
434 OnInstantMessage(user.ControllingClient, msg); 467 new InventoryItemBase(itemID, recipientID);
468 InventoryItemBase item =
469 scene.InventoryService.GetItem(given);
435 470
471 if (item != null)
472 {
473 user.ControllingClient.SendBulkUpdateInventory(item);
474 }
475 }
476 user.ControllingClient.SendInstantMessage(im);
477 }
478 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted ||
479 im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
480 {
481 user.ControllingClient.SendInstantMessage(im);
482 }
436 } 483 }
437 } 484 }
438} 485}
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index d1d7df2..6532bbb 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -148,14 +148,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
148 (uint)presence.AbsolutePosition.Y, 148 (uint)presence.AbsolutePosition.Y,
149 (uint)presence.AbsolutePosition.Z); 149 (uint)presence.AbsolutePosition.Z);
150 150
151 m_log.DebugFormat("TP invite with message {0}", message); 151 m_log.DebugFormat("[LURE]: TP invite with message {0}", message);
152 152
153 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, 153 GridInstantMessage m;
154 client.FirstName+" "+client.LastName, targetid, 154
155 (byte)InstantMessageDialog.RequestTeleport, false, 155 if (scene.Permissions.IsAdministrator(client.AgentId) && presence.GodLevel >= 200 && (!scene.Permissions.IsAdministrator(targetid)))
156 message, dest, false, presence.AbsolutePosition, 156 {
157 new Byte[0]); 157 m = new GridInstantMessage(scene, client.AgentId,
158 158 client.FirstName+" "+client.LastName, targetid,
159 (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
160 message, dest, false, presence.AbsolutePosition,
161 new Byte[0]);
162 }
163 else
164 {
165 m = new GridInstantMessage(scene, client.AgentId,
166 client.FirstName+" "+client.LastName, targetid,
167 (byte)InstantMessageDialog.RequestTeleport, false,
168 message, dest, false, presence.AbsolutePosition,
169 new Byte[0]);
170 }
171
159 if (m_TransferModule != null) 172 if (m_TransferModule != null)
160 { 173 {
161 m_TransferModule.SendInstantMessage(m, 174 m_TransferModule.SendInstantMessage(m,
@@ -190,7 +203,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
190 { 203 {
191 // Forward remote teleport requests 204 // Forward remote teleport requests
192 // 205 //
193 if (msg.dialog != 22) 206 if (msg.dialog != (byte)InstantMessageDialog.RequestTeleport &&
207 msg.dialog != (byte)InstantMessageDialog.GodLikeRequestTeleport)
194 return; 208 return;
195 209
196 if (m_TransferModule != null) 210 if (m_TransferModule != null)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index e5cefe4..eb150d9 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -99,7 +99,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
99 99
100 protected virtual void OnNewClient(IClientAPI client) 100 protected virtual void OnNewClient(IClientAPI client)
101 { 101 {
102 client.OnTeleportHomeRequest += TeleportHome; 102 client.OnTeleportHomeRequest += TeleportHomeFired;
103 } 103 }
104 104
105 public virtual void Close() 105 public virtual void Close()
@@ -268,7 +268,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
268 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 268 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
269 // it's actually doing a lot of work. 269 // it's actually doing a lot of work.
270 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 270 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
271 if (endPoint.Address != null) 271 if (endPoint != null && endPoint.Address != null)
272 { 272 {
273 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 273 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
274 // both regions 274 // both regions
@@ -505,7 +505,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
505 505
506 protected void KillEntity(Scene scene, uint localID) 506 protected void KillEntity(Scene scene, uint localID)
507 { 507 {
508 scene.SendKillObject(localID); 508 scene.SendKillObject(new List<uint>() { localID });
509 } 509 }
510 510
511 protected virtual GridRegion GetFinalDestination(GridRegion region) 511 protected virtual GridRegion GetFinalDestination(GridRegion region)
@@ -543,7 +543,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
543 543
544 #region Teleport Home 544 #region Teleport Home
545 545
546 public virtual void TeleportHome(UUID id, IClientAPI client) 546 public void TeleportHomeFired(UUID id, IClientAPI client)
547 {
548 TeleportHome(id, client);
549 }
550
551 public virtual bool TeleportHome(UUID id, IClientAPI client)
547 { 552 {
548 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 553 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
549 554
@@ -552,12 +557,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
552 557
553 if (uinfo != null) 558 if (uinfo != null)
554 { 559 {
560 if (uinfo.HomeRegionID == UUID.Zero)
561 {
562 // can't find the Home region: Tell viewer and abort
563 client.SendTeleportFailed("You don't have a home position set.");
564 return false;
565 }
555 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 566 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
556 if (regionInfo == null) 567 if (regionInfo == null)
557 { 568 {
558 // can't find the Home region: Tell viewer and abort 569 // can't find the Home region: Tell viewer and abort
559 client.SendTeleportFailed("Your home region could not be found."); 570 client.SendTeleportFailed("Your home region could not be found.");
560 return; 571 return false;
561 } 572 }
562 573
563 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})", 574 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})",
@@ -568,6 +579,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
568 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 579 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
569 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 580 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
570 } 581 }
582 else
583 {
584 // can't find the Home region: Tell viewer and abort
585 client.SendTeleportFailed("Your home region could not be found.");
586 return false;
587 }
588 return true;
571 } 589 }
572 590
573 #endregion 591 #endregion
@@ -852,15 +870,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
852 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 870 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
853 871
854 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>(); 872 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>();
855 if (eq != null) 873 IPEndPoint neighbourExternal = neighbourRegion.ExternalEndPoint;
874 if (neighbourExternal != null)
856 { 875 {
857 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, 876 if (eq != null)
858 capsPath, agent.UUID, agent.ControllingClient.SessionId); 877 {
859 } 878 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
860 else 879 capsPath, agent.UUID, agent.ControllingClient.SessionId);
861 { 880 }
862 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, 881 else
863 capsPath); 882 {
883 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
884 capsPath);
885 }
864 } 886 }
865 887
866 if (!WaitForCallback(agent.UUID)) 888 if (!WaitForCallback(agent.UUID))
@@ -964,10 +986,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
964 agent.Id0 = currentAgentCircuit.Id0; 986 agent.Id0 = currentAgentCircuit.Id0;
965 } 987 }
966 988
967 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 989 IPEndPoint external = region.ExternalEndPoint;
968 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 990 if (external != null)
991 {
992 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
993 d.BeginInvoke(sp, agent, region, external, true,
969 InformClientOfNeighbourCompleted, 994 InformClientOfNeighbourCompleted,
970 d); 995 d);
996 }
971 } 997 }
972 #endregion 998 #endregion
973 999
@@ -1100,6 +1126,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1100 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1126 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1101 try 1127 try
1102 { 1128 {
1129 //neighbour.ExternalEndPoint may return null, which will be caught
1103 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, 1130 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
1104 InformClientOfNeighbourCompleted, 1131 InformClientOfNeighbourCompleted,
1105 d); 1132 d);
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 35dcd95..c75bc0a 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
86 86
87 protected override void OnNewClient(IClientAPI client) 87 protected override void OnNewClient(IClientAPI client)
88 { 88 {
89 client.OnTeleportHomeRequest += TeleportHome; 89 client.OnTeleportHomeRequest += TeleportHomeFired;
90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
91 } 91 }
92 92
@@ -177,7 +177,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
177 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason); 177 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason);
178 } 178 }
179 179
180 public override void TeleportHome(UUID id, IClientAPI client) 180 public void TeleportHomeFired(UUID id, IClientAPI client)
181 {
182 TeleportHome(id, client);
183 }
184
185 public override bool TeleportHome(UUID id, IClientAPI client)
181 { 186 {
182 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 187 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
183 188
@@ -187,8 +192,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
187 { 192 {
188 // local grid user 193 // local grid user
189 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 194 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
190 base.TeleportHome(id, client); 195 return base.TeleportHome(id, client);
191 return;
192 } 196 }
193 197
194 // Foreign user wants to go home 198 // Foreign user wants to go home
@@ -198,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
198 { 202 {
199 client.SendTeleportFailed("Your information has been lost"); 203 client.SendTeleportFailed("Your information has been lost");
200 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 204 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
201 return; 205 return false;
202 } 206 }
203 207
204 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 208 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
@@ -208,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
208 { 212 {
209 client.SendTeleportFailed("Your home region could not be found"); 213 client.SendTeleportFailed("Your home region could not be found");
210 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 214 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
211 return; 215 return false;
212 } 216 }
213 217
214 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 218 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -216,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
216 { 220 {
217 client.SendTeleportFailed("Internal error"); 221 client.SendTeleportFailed("Internal error");
218 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
219 return; 223 return false;
220 } 224 }
221 225
222 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); 226 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
@@ -226,6 +230,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
226 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName); 230 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName);
227 231
228 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); 232 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq);
233 return true;
229 } 234 }
230 #endregion 235 #endregion
231 236
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 1ebccd1..623cd3a 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Net; 30using System.Net;
31using System.Xml;
31using System.Reflection; 32using System.Reflection;
32using System.Threading; 33using System.Threading;
33 34
@@ -202,11 +203,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
202 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, 203 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID,
203 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient) 204 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient)
204 { 205 {
205 // HACK: This is only working for lists containing a single item!
206 // It's just a hack to make this WIP compile and run. Nothing
207 // currently calls this with multiple items.
208 UUID ret = UUID.Zero; 206 UUID ret = UUID.Zero;
209 207
208 // The following code groups the SOG's by owner. No objects
209 // belonging to different people can be coalesced, for obvious
210 // reasons.
210 Dictionary<UUID, List<SceneObjectGroup>> deletes = 211 Dictionary<UUID, List<SceneObjectGroup>> deletes =
211 new Dictionary<UUID, List<SceneObjectGroup>>(); 212 new Dictionary<UUID, List<SceneObjectGroup>>();
212 213
@@ -218,265 +219,340 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
218 deletes[g.OwnerID].Add(g); 219 deletes[g.OwnerID].Add(g);
219 } 220 }
220 221
222 // This is pethod scoped and will be returned. It will be the
223 // last created asset id
224 UUID assetID = UUID.Zero;
225
226 // Each iteration is really a separate asset being created,
227 // with distinct destinations as well.
221 foreach (List<SceneObjectGroup> objlist in deletes.Values) 228 foreach (List<SceneObjectGroup> objlist in deletes.Values)
222 { 229 {
223 foreach (SceneObjectGroup g in objlist) 230 Dictionary<UUID, string> xmlStrings =
224 ret = DeleteToInventory(action, folderID, g, remoteClient); 231 new Dictionary<UUID, string>();
225 }
226
227 return ret;
228 }
229 232
230 private UUID DeleteToInventory(DeRezAction action, UUID folderID, 233 foreach (SceneObjectGroup objectGroup in objlist)
231 SceneObjectGroup objectGroup, IClientAPI remoteClient) 234 {
232 { 235 Vector3 inventoryStoredPosition = new Vector3
233 UUID assetID = UUID.Zero; 236 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
237 ? 250
238 : objectGroup.AbsolutePosition.X)
239 ,
240 (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
241 ? 250
242 : objectGroup.AbsolutePosition.X,
243 objectGroup.AbsolutePosition.Z);
234 244
235 Vector3 inventoryStoredPosition = new Vector3 245 Vector3 originalPosition = objectGroup.AbsolutePosition;
236 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
237 ? 250
238 : objectGroup.AbsolutePosition.X)
239 ,
240 (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
241 ? 250
242 : objectGroup.AbsolutePosition.X,
243 objectGroup.AbsolutePosition.Z);
244 246
245 Vector3 originalPosition = objectGroup.AbsolutePosition; 247 // Restore attachment data after trip through the sim
248 if (objectGroup.RootPart.AttachPoint > 0)
249 inventoryStoredPosition = objectGroup.RootPart.AttachOffset;
250 objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
246 251
247 objectGroup.AbsolutePosition = inventoryStoredPosition; 252 objectGroup.AbsolutePosition = inventoryStoredPosition;
248 253
249 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); 254 // Make sure all bits but the ones we want are clear
255 // on take.
256 // This will be applied to the current perms, so
257 // it will do what we want.
258 objectGroup.RootPart.NextOwnerMask &=
259 ((uint)PermissionMask.Copy |
260 (uint)PermissionMask.Transfer |
261 (uint)PermissionMask.Modify);
262 objectGroup.RootPart.NextOwnerMask |=
263 (uint)PermissionMask.Move;
250 264
251 objectGroup.AbsolutePosition = originalPosition; 265 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup);
252 266
253 // Get the user info of the item destination 267 objectGroup.AbsolutePosition = originalPosition;
254 //
255 UUID userID = UUID.Zero;
256 268
257 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy || 269 xmlStrings[objectGroup.UUID] = sceneObjectXml;
258 action == DeRezAction.SaveToExistingUserInventoryItem) 270 }
259 {
260 // Take or take copy require a taker
261 // Saving changes requires a local user
262 //
263 if (remoteClient == null)
264 return UUID.Zero;
265 271
266 userID = remoteClient.AgentId; 272 string itemXml;
267 }
268 else
269 {
270 // All returns / deletes go to the object owner
271 //
272 273
273 userID = objectGroup.RootPart.OwnerID; 274 if (objlist.Count > 1)
274 } 275 {
276 float minX, minY, minZ;
277 float maxX, maxY, maxZ;
275 278
276 if (userID == UUID.Zero) // Can't proceed 279 Vector3[] offsets = m_Scene.GetCombinedBoundingBox(objlist,
277 { 280 out minX, out maxX, out minY, out maxY,
278 return UUID.Zero; 281 out minZ, out maxZ);
279 }
280 282
281 // If we're returning someone's item, it goes back to the 283 // CreateWrapper
282 // owner's Lost And Found folder. 284 XmlDocument itemDoc = new XmlDocument();
283 // Delete is treated like return in this case 285 XmlElement root = itemDoc.CreateElement("", "CoalescedObject", "");
284 // Deleting your own items makes them go to trash 286 itemDoc.AppendChild(root);
285 //
286 287
287 InventoryFolderBase folder = null; 288 // Embed the offsets into the group XML
288 InventoryItemBase item = null; 289 for ( int i = 0 ; i < objlist.Count ; i++ )
290 {
291 XmlDocument doc = new XmlDocument();
292 SceneObjectGroup g = objlist[i];
293 doc.LoadXml(xmlStrings[g.UUID]);
294 XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup");
295 e.SetAttribute("offsetx", offsets[i].X.ToString());
296 e.SetAttribute("offsety", offsets[i].Y.ToString());
297 e.SetAttribute("offsetz", offsets[i].Z.ToString());
298
299 XmlNode objectNode = itemDoc.ImportNode(e, true);
300 root.AppendChild(objectNode);
301 }
289 302
290 if (DeRezAction.SaveToExistingUserInventoryItem == action) 303 float sizeX = maxX - minX;
291 { 304 float sizeY = maxY - minY;
292 item = new InventoryItemBase(objectGroup.RootPart.FromUserInventoryItemID, userID); 305 float sizeZ = maxZ - minZ;
293 item = m_Scene.InventoryService.GetItem(item);
294 306
295 //item = userInfo.RootFolder.FindItem( 307 root.SetAttribute("x", sizeX.ToString());
296 // objectGroup.RootPart.FromUserInventoryItemID); 308 root.SetAttribute("y", sizeY.ToString());
309 root.SetAttribute("z", sizeZ.ToString());
297 310
298 if (null == item) 311 itemXml = itemDoc.InnerXml;
312 }
313 else
299 { 314 {
300 m_log.DebugFormat( 315 itemXml = xmlStrings[objlist[0].UUID];
301 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
302 objectGroup.Name, objectGroup.UUID);
303 return UUID.Zero;
304 } 316 }
305 } 317
306 else 318 // Get the user info of the item destination
307 {
308 // Folder magic
309 // 319 //
310 if (action == DeRezAction.Delete) 320 UUID userID = UUID.Zero;
321
322 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
323 action == DeRezAction.SaveToExistingUserInventoryItem)
311 { 324 {
312 // Deleting someone else's item 325 // Take or take copy require a taker
326 // Saving changes requires a local user
313 // 327 //
314 if (remoteClient == null || 328 if (remoteClient == null)
315 objectGroup.OwnerID != remoteClient.AgentId) 329 return UUID.Zero;
316 {
317 330
318 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 331 userID = remoteClient.AgentId;
319 }
320 else
321 {
322 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
323 }
324 } 332 }
325 else if (action == DeRezAction.Return) 333 else
326 { 334 {
327 335 // All returns / deletes go to the object owner
328 // Dump to lost + found unconditionally
329 // 336 //
330 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 337
338 userID = objlist[0].RootPart.OwnerID;
331 } 339 }
332 340
333 if (folderID == UUID.Zero && folder == null) 341 if (userID == UUID.Zero) // Can't proceed
334 { 342 {
335 if (action == DeRezAction.Delete) 343 return UUID.Zero;
344 }
345
346 // If we're returning someone's item, it goes back to the
347 // owner's Lost And Found folder.
348 // Delete is treated like return in this case
349 // Deleting your own items makes them go to trash
350 //
351
352 InventoryFolderBase folder = null;
353 InventoryItemBase item = null;
354
355 if (DeRezAction.SaveToExistingUserInventoryItem == action)
356 {
357 item = new InventoryItemBase(objlist[0].RootPart.FromUserInventoryItemID, userID);
358 item = m_Scene.InventoryService.GetItem(item);
359
360 //item = userInfo.RootFolder.FindItem(
361 // objectGroup.RootPart.FromUserInventoryItemID);
362
363 if (null == item)
336 { 364 {
337 // Deletes go to trash by default 365 m_log.DebugFormat(
338 // 366 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
339 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 367 objlist[0].Name, objlist[0].UUID);
368 return UUID.Zero;
340 } 369 }
341 else 370 }
371 else
372 {
373 // Folder magic
374 //
375 if (action == DeRezAction.Delete)
342 { 376 {
377 // Deleting someone else's item
378 //
343 if (remoteClient == null || 379 if (remoteClient == null ||
344 objectGroup.OwnerID != remoteClient.AgentId) 380 objlist[0].OwnerID != remoteClient.AgentId)
345 { 381 {
346 // Taking copy of another person's item. Take to 382
347 // Objects folder. 383 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
348 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
349 } 384 }
350 else 385 else
351 { 386 {
352 // Catch all. Use lost & found 387 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
388 }
389 }
390 else if (action == DeRezAction.Return)
391 {
392
393 // Dump to lost + found unconditionally
394 //
395 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
396 }
397
398 if (folderID == UUID.Zero && folder == null)
399 {
400 if (action == DeRezAction.Delete)
401 {
402 // Deletes go to trash by default
353 // 403 //
404 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
405 }
406 else
407 {
408 if (remoteClient == null ||
409 objlist[0].OwnerID != remoteClient.AgentId)
410 {
411 // Taking copy of another person's item. Take to
412 // Objects folder.
413 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
414 }
415 else
416 {
417 // Catch all. Use lost & found
418 //
354 419
355 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 420 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
421 }
356 } 422 }
357 } 423 }
358 }
359 424
360 // Override and put into where it came from, if it came 425 // Override and put into where it came from, if it came
361 // from anywhere in inventory 426 // from anywhere in inventory
362 // 427 //
363 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 428 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
364 {
365 if (objectGroup.RootPart.FromFolderID != UUID.Zero)
366 { 429 {
367 InventoryFolderBase f = new InventoryFolderBase(objectGroup.RootPart.FromFolderID, userID); 430 if (objlist[0].RootPart.FromFolderID != UUID.Zero && objlist[0].OwnerID == remoteClient.AgentId)
368 folder = m_Scene.InventoryService.GetFolder(f); 431 {
432 InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID);
433 folder = m_Scene.InventoryService.GetFolder(f);
434 }
369 } 435 }
370 }
371 436
372 if (folder == null) // None of the above 437 if (folder == null) // None of the above
373 { 438 {
374 folder = new InventoryFolderBase(folderID); 439 folder = new InventoryFolderBase(folderID);
375 440
376 if (folder == null) // Nowhere to put it 441 if (folder == null) // Nowhere to put it
442 {
443 return UUID.Zero;
444 }
445 }
446
447 item = new InventoryItemBase();
448 // Can't know creator is the same, so null it in inventory
449 if (objlist.Count > 1)
377 { 450 {
378 return UUID.Zero; 451 item.CreatorId = UUID.Zero.ToString();
452 item.CreatorData = String.Empty;
453 }
454 else
455 {
456 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
457 item.CreatorData = objlist[0].RootPart.CreatorData;
458 }
459 item.ID = UUID.Random();
460 item.InvType = (int)InventoryType.Object;
461 item.Folder = folder.ID;
462 item.Owner = userID;
463 if (objlist.Count > 1)
464 {
465 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
466 }
467 else
468 {
469 item.SaleType = objlist[0].RootPart.ObjectSaleType;
470 item.SalePrice = objlist[0].RootPart.SalePrice;
379 } 471 }
380 } 472 }
381 473
382 item = new InventoryItemBase(); 474 AssetBase asset = CreateAsset(
383 item.CreatorId = objectGroup.RootPart.CreatorID.ToString(); 475 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
384 item.CreatorData = objectGroup.RootPart.CreatorData; 476 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
385 item.ID = UUID.Random(); 477 (sbyte)AssetType.Object,
386 item.InvType = (int)InventoryType.Object; 478 Utils.StringToBytes(itemXml),
387 item.Folder = folder.ID; 479 objlist[0].OwnerID.ToString());
388 item.Owner = userID; 480 m_Scene.AssetService.Store(asset);
389 } 481 assetID = asset.FullID;
390
391 AssetBase asset = CreateAsset(
392 objectGroup.GetPartName(objectGroup.RootPart.LocalId),
393 objectGroup.GetPartDescription(objectGroup.RootPart.LocalId),
394 (sbyte)AssetType.Object,
395 Utils.StringToBytes(sceneObjectXml),
396 objectGroup.OwnerID.ToString());
397 m_Scene.AssetService.Store(asset);
398 assetID = asset.FullID;
399
400 if (DeRezAction.SaveToExistingUserInventoryItem == action)
401 {
402 item.AssetID = asset.FullID;
403 m_Scene.InventoryService.UpdateItem(item);
404 }
405 else
406 {
407 item.AssetID = asset.FullID;
408 482
409 if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 483 if (DeRezAction.SaveToExistingUserInventoryItem == action)
410 { 484 {
411 uint perms = objectGroup.GetEffectivePermissions(); 485 item.AssetID = asset.FullID;
412 uint nextPerms = (perms & 7) << 13; 486 m_Scene.InventoryService.UpdateItem(item);
413 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
414 perms &= ~(uint)PermissionMask.Copy;
415 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
416 perms &= ~(uint)PermissionMask.Transfer;
417 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
418 perms &= ~(uint)PermissionMask.Modify;
419
420 // Make sure all bits but the ones we want are clear
421 // on take.
422 // This will be applied to the current perms, so
423 // it will do what we want.
424 objectGroup.RootPart.NextOwnerMask &=
425 ((uint)PermissionMask.Copy |
426 (uint)PermissionMask.Transfer |
427 (uint)PermissionMask.Modify);
428 objectGroup.RootPart.NextOwnerMask |=
429 (uint)PermissionMask.Move;
430
431 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
432 item.CurrentPermissions = item.BasePermissions;
433 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
434 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
435 item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask;
436
437 // Magic number badness. Maybe this deserves an enum.
438 // bit 4 (16) is the "Slam" bit, it means treat as passed
439 // and apply next owner perms on rez
440 item.CurrentPermissions |= 16; // Slam!
441 } 487 }
442 else 488 else
443 { 489 {
444 item.BasePermissions = objectGroup.GetEffectivePermissions(); 490 item.AssetID = asset.FullID;
445 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
446 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
447 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
448 item.GroupPermissions = objectGroup.RootPart.GroupMask;
449 491
450 item.CurrentPermissions &= 492 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7;
451 ((uint)PermissionMask.Copy | 493 foreach (SceneObjectGroup grp in objlist)
452 (uint)PermissionMask.Transfer | 494 effectivePerms &= grp.GetEffectivePermissions();
453 (uint)PermissionMask.Modify | 495 effectivePerms |= (uint)PermissionMask.Move;
454 (uint)PermissionMask.Move |
455 7); // Preserve folded permissions
456 }
457 496
458 // TODO: add the new fields (Flags, Sale info, etc) 497 if (remoteClient != null && (remoteClient.AgentId != objlist[0].RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
459 item.CreationDate = Util.UnixTimeSinceEpoch(); 498 {
460 item.Description = asset.Description; 499 uint perms = effectivePerms;
461 item.Name = asset.Name; 500 uint nextPerms = (perms & 7) << 13;
462 item.AssetType = asset.Type; 501 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
502 perms &= ~(uint)PermissionMask.Copy;
503 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
504 perms &= ~(uint)PermissionMask.Transfer;
505 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
506 perms &= ~(uint)PermissionMask.Modify;
507
508 item.BasePermissions = perms & objlist[0].RootPart.NextOwnerMask;
509 item.CurrentPermissions = item.BasePermissions;
510 item.NextPermissions = perms & objlist[0].RootPart.NextOwnerMask;
511 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask;
512 item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask;
513
514 // Magic number badness. Maybe this deserves an enum.
515 // bit 4 (16) is the "Slam" bit, it means treat as passed
516 // and apply next owner perms on rez
517 item.CurrentPermissions |= 16; // Slam!
518 }
519 else
520 {
521 item.BasePermissions = effectivePerms;
522 item.CurrentPermissions = effectivePerms;
523 item.NextPermissions = objlist[0].RootPart.NextOwnerMask & effectivePerms;
524 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & effectivePerms;
525 item.GroupPermissions = objlist[0].RootPart.GroupMask & effectivePerms;
526
527 item.CurrentPermissions &=
528 ((uint)PermissionMask.Copy |
529 (uint)PermissionMask.Transfer |
530 (uint)PermissionMask.Modify |
531 (uint)PermissionMask.Move |
532 7); // Preserve folded permissions
533 }
463 534
464 m_Scene.AddInventoryItem(item); 535 item.CreationDate = Util.UnixTimeSinceEpoch();
536 item.Description = asset.Description;
537 item.Name = asset.Name;
538 item.AssetType = asset.Type;
465 539
466 if (remoteClient != null && item.Owner == remoteClient.AgentId) 540 m_Scene.AddInventoryItem(item);
467 { 541
468 remoteClient.SendInventoryItemCreateUpdate(item, 0); 542 if (remoteClient != null && item.Owner == remoteClient.AgentId)
469 }
470 else
471 {
472 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
473 if (notifyUser != null)
474 { 543 {
475 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); 544 remoteClient.SendInventoryItemCreateUpdate(item, 0);
545 }
546 else
547 {
548 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
549 if (notifyUser != null)
550 {
551 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
552 }
476 } 553 }
477 } 554 }
478 } 555 }
479
480 return assetID; 556 return assetID;
481 } 557 }
482 558
@@ -527,8 +603,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
527 603
528 if (item != null) 604 if (item != null)
529 { 605 {
606 if (item.ID == UUID.Zero)
607 {
608 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 1");
609 }
610
530 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); 611 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
531 612
613 SceneObjectGroup group = null;
614
532 if (rezAsset != null) 615 if (rezAsset != null)
533 { 616 {
534 UUID itemId = UUID.Zero; 617 UUID itemId = UUID.Zero;
@@ -537,34 +620,83 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
537 // item that it came from. This allows us to enable 'save object to inventory' 620 // item that it came from. This allows us to enable 'save object to inventory'
538 if (!m_Scene.Permissions.BypassPermissions()) 621 if (!m_Scene.Permissions.BypassPermissions())
539 { 622 {
540 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy) 623 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
541 { 624 {
542 itemId = item.ID; 625 itemId = item.ID;
543 } 626 }
544 } 627 }
545 else 628 else
546 { 629 {
547 // Brave new fullperm world 630 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
548 // 631 {
549 itemId = item.ID; 632 // Brave new fullperm world
633 itemId = item.ID;
634 }
635 }
636
637 if (item.ID == UUID.Zero)
638 {
639 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 2");
550 } 640 }
551 641
552 string xmlData = Utils.BytesToString(rezAsset.Data); 642 string xmlData = Utils.BytesToString(rezAsset.Data);
553 SceneObjectGroup group 643 List<SceneObjectGroup> objlist =
554 = SceneObjectSerializer.FromOriginalXmlFormat(itemId, xmlData); 644 new List<SceneObjectGroup>();
645 List<Vector3> veclist = new List<Vector3>();
646
647 XmlDocument doc = new XmlDocument();
648 doc.LoadXml(xmlData);
649 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
650 if (e == null || attachment) // Single
651 {
652 SceneObjectGroup g =
653 SceneObjectSerializer.FromOriginalXmlFormat(
654 itemId, xmlData);
655 objlist.Add(g);
656 veclist.Add(new Vector3(0, 0, 0));
657
658 float offsetHeight = 0;
659 pos = m_Scene.GetNewRezLocation(
660 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
661 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
662 pos.Z += offsetHeight;
663 }
664 else
665 {
666 XmlElement coll = (XmlElement)e;
667 float bx = Convert.ToSingle(coll.GetAttribute("x"));
668 float by = Convert.ToSingle(coll.GetAttribute("y"));
669 float bz = Convert.ToSingle(coll.GetAttribute("z"));
670 Vector3 bbox = new Vector3(bx, by, bz);
555 671
556 Util.FireAndForget(delegate { AddUserData(group); }); 672 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
557 673 RayTargetID, Quaternion.Identity,
558 group.RootPart.FromFolderID = item.Folder; 674 BypassRayCast, bRayEndIsIntersection, true,
675 bbox, false);
559 676
560 // If it's rezzed in world, select it. Much easier to 677 pos -= bbox / 2;
561 // find small items. 678
562 // 679 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
563 if (!attachment) 680 foreach (XmlNode n in groups)
564 group.RootPart.CreateSelected = true; 681 {
682 SceneObjectGroup g =
683 SceneObjectSerializer.FromOriginalXmlFormat(
684 itemId, n.OuterXml);
685 objlist.Add(g);
686 XmlElement el = (XmlElement)n;
687 float x = Convert.ToSingle(el.GetAttribute("offsetx"));
688 float y = Convert.ToSingle(el.GetAttribute("offsety"));
689 float z = Convert.ToSingle(el.GetAttribute("offsetz"));
690 veclist.Add(new Vector3(x, y, z));
691 }
692 }
693
694 int primcount = 0;
695 foreach (SceneObjectGroup g in objlist)
696 primcount += g.PrimCount;
565 697
566 if (!m_Scene.Permissions.CanRezObject( 698 if (!m_Scene.Permissions.CanRezObject(
567 group.PrimCount, remoteClient.AgentId, pos) 699 primcount, remoteClient.AgentId, pos)
568 && !attachment) 700 && !attachment)
569 { 701 {
570 // The client operates in no fail mode. It will 702 // The client operates in no fail mode. It will
@@ -577,116 +709,147 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
577 return null; 709 return null;
578 } 710 }
579 711
580 group.ResetIDs(); 712 for (int i = 0 ; i < objlist.Count ; i++ )
581
582 if (attachment)
583 {
584 group.RootPart.Flags |= PrimFlags.Phantom;
585 group.RootPart.IsAttachment = true;
586
587 // If we're rezzing an attachment then don't ask
588 // AddNewSceneObject() to update the client since
589 // we'll be doing that later on. Scheduling more
590 // than one full update during the attachment
591 // process causes some clients to fail to display
592 // the attachment properly.
593 // Also, don't persist attachments.
594 m_Scene.AddNewSceneObject(group, false, false);
595 }
596 else
597 { 713 {
598 m_Scene.AddNewSceneObject(group, true, false); 714 group = objlist[i];
599 }
600 715
601 // m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z); 716 Vector3 storedPosition = group.AbsolutePosition;
602 // if attachment we set it's asset id so object updates can reflect that 717 if (group.UUID == UUID.Zero)
603 // if not, we set it's position in world. 718 {
604 if (!attachment) 719 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 3");
605 { 720 }
606 group.ScheduleGroupForFullUpdate(); 721 group.RootPart.FromFolderID = item.Folder;
607
608 float offsetHeight = 0;
609 pos = m_Scene.GetNewRezLocation(
610 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
611 BypassRayCast, bRayEndIsIntersection, true, group.GetAxisAlignedBoundingBox(out offsetHeight), false);
612 pos.Z += offsetHeight;
613 group.AbsolutePosition = pos;
614 // m_log.InfoFormat("rezx point for inventory rezz is {0} {1} {2} and offsetheight was {3}", pos.X, pos.Y, pos.Z, offsetHeight);
615 722
616 } 723 // If it's rezzed in world, select it. Much easier to
617 else 724 // find small items.
618 { 725 //
619 group.SetFromItemID(itemID); 726 if (!attachment)
620 } 727 {
728 group.RootPart.CreateSelected = true;
729 foreach (SceneObjectPart child in group.Parts)
730 child.CreateSelected = true;
731 }
621 732
622 SceneObjectPart rootPart = null; 733 group.ResetIDs();
623 try
624 {
625 rootPart = group.GetChildPart(group.UUID);
626 }
627 catch (NullReferenceException)
628 {
629 string isAttachment = "";
630 734
631 if (attachment) 735 if (attachment)
632 isAttachment = " Object was an attachment"; 736 {
737 group.RootPart.Flags |= PrimFlags.Phantom;
738 group.RootPart.IsAttachment = true;
739
740 // If we're rezzing an attachment then don't ask
741 // AddNewSceneObject() to update the client since
742 // we'll be doing that later on. Scheduling more
743 // than one full update during the attachment
744 // process causes some clients to fail to display
745 // the attachment properly.
746 // Also, don't persist attachments.
747 m_Scene.AddNewSceneObject(group, false, false);
748 }
749 else
750 {
751 m_Scene.AddNewSceneObject(group, true, false);
752 }
633 753
634 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment); 754 // if attachment we set it's asset id so object updates
635 } 755 // can reflect that, if not, we set it's position in world.
756 if (!attachment)
757 {
758 group.ScheduleGroupForFullUpdate();
759
760 group.AbsolutePosition = pos + veclist[i];
761 }
762 else
763 {
764 group.SetFromItemID(itemID);
765 }
636 766
637 // Since renaming the item in the inventory does not affect the name stored 767 SceneObjectPart rootPart = null;
638 // in the serialization, transfer the correct name from the inventory to the
639 // object itself before we rez.
640 rootPart.Name = item.Name;
641 rootPart.Description = item.Description;
642 768
643 group.SetGroup(remoteClient.ActiveGroupId, remoteClient); 769 try
644 if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0) 770 {
645 { 771 rootPart = group.GetChildPart(group.UUID);
646 //Need to kill the for sale here 772 }
647 rootPart.ObjectSaleType = 0; 773 catch (NullReferenceException)
648 rootPart.SalePrice = 10; 774 {
775 string isAttachment = "";
649 776
650 if (m_Scene.Permissions.PropagatePermissions()) 777 if (attachment)
778 isAttachment = " Object was an attachment";
779
780 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment);
781 }
782
783 // Since renaming the item in the inventory does not
784 // affect the name stored in the serialization, transfer
785 // the correct name from the inventory to the
786 // object itself before we rez.
787 // On coalesced objects, this has no effect.
788 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
789 {
790 rootPart.Name = item.Name;
791 rootPart.Description = item.Description;
792 rootPart.ObjectSaleType = item.SaleType;
793 rootPart.SalePrice = item.SalePrice;
794 }
795
796 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
797 if ((rootPart.OwnerID != item.Owner) ||
798 (item.CurrentPermissions & 16) != 0)
651 { 799 {
652 foreach (SceneObjectPart part in group.Parts) 800 //Need to kill the for sale here
801 rootPart.ObjectSaleType = 0;
802 rootPart.SalePrice = 10;
803
804 if (m_Scene.Permissions.PropagatePermissions())
653 { 805 {
654 part.EveryoneMask = item.EveryOnePermissions; 806 foreach (SceneObjectPart part in group.Parts)
655 part.NextOwnerMask = item.NextPermissions; 807 {
656 part.GroupMask = 0; // DO NOT propagate here 808 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
809 {
810 part.EveryoneMask = item.EveryOnePermissions;
811 part.NextOwnerMask = item.NextPermissions;
812 }
813 part.GroupMask = 0; // DO NOT propagate here
814 }
815
816 group.ApplyNextOwnerPermissions();
657 } 817 }
658
659 group.ApplyNextOwnerPermissions();
660 } 818 }
661 }
662 819
663 foreach (SceneObjectPart part in group.Parts) 820 foreach (SceneObjectPart part in group.Parts)
664 {
665 if ((part.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0)
666 { 821 {
667 part.LastOwnerID = part.OwnerID; 822 if ((part.OwnerID != item.Owner) ||
668 part.OwnerID = item.Owner; 823 (item.CurrentPermissions & 16) != 0)
669 part.Inventory.ChangeInventoryOwner(item.Owner); 824 {
670 part.GroupMask = 0; // DO NOT propagate here 825 part.LastOwnerID = part.OwnerID;
826 part.OwnerID = item.Owner;
827 part.Inventory.ChangeInventoryOwner(item.Owner);
828 part.GroupMask = 0; // DO NOT propagate here
829 }
830 part.EveryoneMask = item.EveryOnePermissions;
831 part.NextOwnerMask = item.NextPermissions;
671 } 832 }
672 part.EveryoneMask = item.EveryOnePermissions;
673 part.NextOwnerMask = item.NextPermissions;
674 }
675 833
676 rootPart.TrimPermissions(); 834 rootPart.TrimPermissions();
677 835
678 if (!attachment) 836 if (!attachment)
679 {
680 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
681 { 837 {
682 group.ClearPartAttachmentData(); 838 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
683 } 839 {
684 840 // Save attachment data
685 // Fire on_rez 841 group.RootPart.AttachPoint = group.RootPart.Shape.State;
686 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); 842 group.RootPart.AttachOffset = storedPosition;
687 rootPart.ParentGroup.ResumeScripts();
688 843
689 rootPart.ScheduleFullUpdate(); 844 group.ClearPartAttachmentData();
845 }
846
847 // Fire on_rez
848 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
849 rootPart.ParentGroup.ResumeScripts();
850
851 rootPart.ScheduleFullUpdate();
852 }
690 } 853 }
691 854
692 if (!m_Scene.Permissions.BypassPermissions()) 855 if (!m_Scene.Permissions.BypassPermissions())
@@ -704,9 +867,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
704 } 867 }
705 } 868 }
706 } 869 }
707
708 return rootPart.ParentGroup;
709 } 870 }
871 return group;
710 } 872 }
711 873
712 return null; 874 return null;
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index d78931a..e4a2461 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -341,6 +341,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
341 try 341 try
342 { 342 {
343 Request = (HttpWebRequest) WebRequest.Create(Url); 343 Request = (HttpWebRequest) WebRequest.Create(Url);
344
345 //This works around some buggy HTTP Servers like Lighttpd
346 Request.ServicePoint.Expect100Continue = false;
347
344 Request.Method = HttpMethod; 348 Request.Method = HttpMethod;
345 Request.ContentType = HttpMIMEType; 349 Request.ContentType = HttpMIMEType;
346 350
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 9b565ed..1fd1f47 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -142,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
142 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 142 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
143 return urlcode; 143 return urlcode;
144 } 144 }
145 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; 145 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString();
146 146
147 UrlData urlData = new UrlData(); 147 UrlData urlData = new UrlData();
148 urlData.hostID = host.UUID; 148 urlData.hostID = host.UUID;
@@ -152,10 +152,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
152 urlData.urlcode = urlcode; 152 urlData.urlcode = urlcode;
153 urlData.requests = new Dictionary<UUID, RequestData>(); 153 urlData.requests = new Dictionary<UUID, RequestData>();
154 154
155
156 m_UrlMap[url] = urlData; 155 m_UrlMap[url] = urlData;
157 156
158 string uri = "/lslhttp/" + urlcode.ToString() + "/"; 157 string uri = "/lslhttp/" + urlcode.ToString();
159 158
160 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll, 159 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll,
161 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents, 160 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents,
@@ -386,6 +385,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
386 385
387 return response; 386 return response;
388 } 387 }
388
389 public void HttpRequestHandler(UUID requestID, Hashtable request) 389 public void HttpRequestHandler(UUID requestID, Hashtable request)
390 { 390 {
391 lock (request) 391 lock (request)
@@ -400,8 +400,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
400 400
401 int pos1 = uri.IndexOf("/");// /lslhttp 401 int pos1 = uri.IndexOf("/");// /lslhttp
402 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 402 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
403 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/ 403 int pos3 = pos2 + 37; // /lslhttp/urlcode
404 string uri_tmp = uri.Substring(0, pos3 + 1); 404 string uri_tmp = uri.Substring(0, pos3);
405 //HTTP server code doesn't provide us with QueryStrings 405 //HTTP server code doesn't provide us with QueryStrings
406 string pathInfo; 406 string pathInfo;
407 string queryString; 407 string queryString;
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index e54ee02..ebfba2b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -57,9 +57,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
57 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); 57 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector");
58 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); 58 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService");
59 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); 59 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
60 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); 60 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion");
61 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); 61 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion");
62 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); 62 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion");
63 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); 63 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion");
64 64
65 m_LocalConnector = new LocalGridServicesConnector(config); 65 m_LocalConnector = new LocalGridServicesConnector(config);
@@ -128,8 +128,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
128 Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); 128 Assert.IsNotNull(result, "Retrieved GetRegionByName is null");
129 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); 129 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match");
130 130
131 m_LocalConnector.RegisterRegion(UUID.Zero, r2); 131 m_LocalConnector.RegisterRegion(UUID.Zero, r2);
132 m_LocalConnector.RegisterRegion(UUID.Zero, r3); 132 m_LocalConnector.RegisterRegion(UUID.Zero, r3);
133 m_LocalConnector.RegisterRegion(UUID.Zero, r4); 133 m_LocalConnector.RegisterRegion(UUID.Zero, r4);
134 134
135 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); 135 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1));
@@ -154,38 +154,38 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
154 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); 154 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null");
155 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); 155 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected");
156 156
157 results = m_LocalConnector.GetDefaultRegions(UUID.Zero); 157 results = m_LocalConnector.GetDefaultRegions(UUID.Zero);
158 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); 158 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null");
159 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); 159 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size");
160 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); 160 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match");
161 161
162 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); 162 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY);
163 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); 163 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null");
164 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); 164 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size");
165 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 165 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
166 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 166 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
167 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 167 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
168 168
169 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); 169 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY);
170 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); 170 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null");
171 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); 171 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size");
172 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); 172 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3");
173 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); 173 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3");
174 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); 174 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3");
175 175
176 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); 176 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY);
177 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); 177 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null");
178 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); 178 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size");
179 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); 179 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2");
180 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); 180 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2");
181 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); 181 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2");
182 182
183 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); 183 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY);
184 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); 184 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null");
185 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); 185 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size");
186 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); 186 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2");
187 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); 187 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2");
188 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); 188 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2");
189 189
190 results = m_LocalConnector.GetHyperlinks(UUID.Zero); 190 results = m_LocalConnector.GetHyperlinks(UUID.Zero);
191 Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); 191 Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null");
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index 37b403e..5be6486 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -307,6 +307,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
307 return false; 307 return false;
308 } 308 }
309 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);
321 }
322 }
323 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
324 return false;
325 }
326
310 /** 327 /**
311 * Object-related communications 328 * Object-related communications
312 */ 329 */
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index 387a9b8..27792c8 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -269,6 +269,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
269 return false; 269 return false;
270 } 270 }
271 271
272 public bool CloseChildAgent(GridRegion destination, UUID id)
273 {
274 if (destination == null)
275 return false;
276
277 // Try local first
278 if (m_localBackend.CloseChildAgent(destination, id))
279 return true;
280
281 // else do the remote thing
282 if (!m_localBackend.IsLocalRegion(destination.RegionHandle))
283 return m_remoteConnector.CloseChildAgent(destination, id);
284
285 return false;
286 }
272 287
273 public bool CloseAgent(GridRegion destination, UUID id) 288 public bool CloseAgent(GridRegion destination, UUID id)
274 { 289 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
index 30ebb21..9ecbcc6 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
@@ -172,6 +172,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
172 return m_UserService.GetUserAccount(scopeID, Email); 172 return m_UserService.GetUserAccount(scopeID, Email);
173 } 173 }
174 174
175 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query)
176 {
177 return null;
178 }
179
175 public List<UserAccount> GetUserAccounts(UUID scopeID, string query) 180 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
176 { 181 {
177 return m_UserService.GetUserAccounts(scopeID, query); 182 return m_UserService.GetUserAccounts(scopeID, query);
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index 3238a81..d948b82 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -287,6 +287,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
287 // being no copy/no mod for everyone 287 // being no copy/no mod for everyone
288 lock (part.TaskInventory) 288 lock (part.TaskInventory)
289 { 289 {
290 if (!ResolveUserUuid(part.CreatorID))
291 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
292
293 if (!ResolveUserUuid(part.OwnerID))
294 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
295
296 if (!ResolveUserUuid(part.LastOwnerID))
297 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
298
299 // And zap any troublesome sit target information
300 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
301 part.SitTargetPosition = new Vector3(0, 0, 0);
302
303 // Fix ownership/creator of inventory items
304 // Not doing so results in inventory items
305 // being no copy/no mod for everyone
306 part.TaskInventory.LockItemsForRead(true);
290 TaskInventoryDictionary inv = part.TaskInventory; 307 TaskInventoryDictionary inv = part.TaskInventory;
291 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 308 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
292 { 309 {
@@ -302,6 +319,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
302 if (UserManager != null) 319 if (UserManager != null)
303 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); 320 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
304 } 321 }
322 part.TaskInventory.LockItemsForRead(false);
305 } 323 }
306 } 324 }
307 325
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index ddae20f..60e8c1a 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Security; 31using System.Security;
32using System.Timers;
32using log4net; 33using log4net;
33using Nini.Config; 34using Nini.Config;
34using OpenMetaverse; 35using OpenMetaverse;
@@ -45,6 +46,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
45 private delegate void LookupUUIDS(List<UUID> uuidLst); 46 private delegate void LookupUUIDS(List<UUID> uuidLst);
46 47
47 private Scene m_scene; 48 private Scene m_scene;
49 private Timer m_regionChangeTimer = new Timer();
48 50
49 private EstateTerrainXferHandler TerrainUploader; 51 private EstateTerrainXferHandler TerrainUploader;
50 52
@@ -246,7 +248,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
246 timeInSeconds -= 15; 248 timeInSeconds -= 15;
247 } 249 }
248 250
249 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); 251 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false);
250 } 252 }
251 } 253 }
252 254
@@ -266,7 +268,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
266 268
267 if ((estateAccessType & 4) != 0) // User add 269 if ((estateAccessType & 4) != 0) // User add
268 { 270 {
269 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 271 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
270 { 272 {
271 m_scene.RegionInfo.EstateSettings.AddEstateUser(user); 273 m_scene.RegionInfo.EstateSettings.AddEstateUser(user);
272 m_scene.RegionInfo.EstateSettings.Save(); 274 m_scene.RegionInfo.EstateSettings.Save();
@@ -281,7 +283,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
281 } 283 }
282 if ((estateAccessType & 8) != 0) // User remove 284 if ((estateAccessType & 8) != 0) // User remove
283 { 285 {
284 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 286 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
285 { 287 {
286 m_scene.RegionInfo.EstateSettings.RemoveEstateUser(user); 288 m_scene.RegionInfo.EstateSettings.RemoveEstateUser(user);
287 m_scene.RegionInfo.EstateSettings.Save(); 289 m_scene.RegionInfo.EstateSettings.Save();
@@ -296,7 +298,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
296 } 298 }
297 if ((estateAccessType & 16) != 0) // Group add 299 if ((estateAccessType & 16) != 0) // Group add
298 { 300 {
299 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 301 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
300 { 302 {
301 m_scene.RegionInfo.EstateSettings.AddEstateGroup(user); 303 m_scene.RegionInfo.EstateSettings.AddEstateGroup(user);
302 m_scene.RegionInfo.EstateSettings.Save(); 304 m_scene.RegionInfo.EstateSettings.Save();
@@ -310,7 +312,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
310 } 312 }
311 if ((estateAccessType & 32) != 0) // Group remove 313 if ((estateAccessType & 32) != 0) // Group remove
312 { 314 {
313 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 315 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
314 { 316 {
315 m_scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); 317 m_scene.RegionInfo.EstateSettings.RemoveEstateGroup(user);
316 m_scene.RegionInfo.EstateSettings.Save(); 318 m_scene.RegionInfo.EstateSettings.Save();
@@ -359,7 +361,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
359 { 361 {
360 if (!s.IsChildAgent) 362 if (!s.IsChildAgent)
361 { 363 {
362 m_scene.TeleportClientHome(user, s.ControllingClient); 364 if (!m_scene.TeleportClientHome(user, s.ControllingClient))
365 {
366 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
367 s.ControllingClient.Close();
368 }
363 } 369 }
364 } 370 }
365 371
@@ -493,7 +499,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
493 ScenePresence s = m_scene.GetScenePresence(prey); 499 ScenePresence s = m_scene.GetScenePresence(prey);
494 if (s != null) 500 if (s != null)
495 { 501 {
496 m_scene.TeleportClientHome(prey, s.ControllingClient); 502 if (!m_scene.TeleportClientHome(prey, s.ControllingClient))
503 {
504 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
505 s.ControllingClient.Close();
506 }
497 } 507 }
498 } 508 }
499 } 509 }
@@ -512,7 +522,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
512 // Also make sure they are actually in the region 522 // Also make sure they are actually in the region
513 if (p != null && !p.IsChildAgent) 523 if (p != null && !p.IsChildAgent)
514 { 524 {
515 m_scene.TeleportClientHome(p.UUID, p.ControllingClient); 525 if (!m_scene.TeleportClientHome(p.UUID, p.ControllingClient))
526 {
527 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
528 p.ControllingClient.Close();
529 }
516 } 530 }
517 } 531 }
518 }); 532 });
@@ -921,6 +935,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
921 m_scene.RegisterModuleInterface<IEstateModule>(this); 935 m_scene.RegisterModuleInterface<IEstateModule>(this);
922 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 936 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
923 m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; 937 m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
938 m_regionChangeTimer.AutoReset = false;
939 m_regionChangeTimer.Interval = 2000;
940 m_regionChangeTimer.Elapsed += RaiseRegionInfoChange;
924 941
925 m_scene.AddCommand(this, "set terrain texture", 942 m_scene.AddCommand(this, "set terrain texture",
926 "set terrain texture <number> <uuid> [<x>] [<y>]", 943 "set terrain texture <number> <uuid> [<x>] [<y>]",
@@ -1193,6 +1210,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1193 1210
1194 protected void TriggerRegionInfoChange() 1211 protected void TriggerRegionInfoChange()
1195 { 1212 {
1213 m_regionChangeTimer.Stop();
1214 m_regionChangeTimer.Start();
1215 }
1216
1217 protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e)
1218 {
1196 ChangeDelegate change = OnRegionInfoChange; 1219 ChangeDelegate change = OnRegionInfoChange;
1197 1220
1198 if (change != null) 1221 if (change != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 4f8e205..d9812df 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -85,6 +85,8 @@ namespace OpenSim.Region.CoreModules.World.Land
85 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 85 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
86 86
87 private bool m_allowedForcefulBans = true; 87 private bool m_allowedForcefulBans = true;
88 private UUID DefaultGodParcelGroup;
89 private string DefaultGodParcelName;
88 90
89 // caches ExtendedLandData 91 // caches ExtendedLandData
90 private Cache parcelInfoCache; 92 private Cache parcelInfoCache;
@@ -100,6 +102,12 @@ namespace OpenSim.Region.CoreModules.World.Land
100 102
101 public void Initialise(IConfigSource source) 103 public void Initialise(IConfigSource source)
102 { 104 {
105 IConfig cnf = source.Configs["LandManagement"];
106 if (cnf != null)
107 {
108 DefaultGodParcelGroup = new UUID(cnf.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
109 DefaultGodParcelName = cnf.GetString("DefaultAdministratorParcelName", "Default Parcel");
110 }
103 } 111 }
104 112
105 public void AddRegion(Scene scene) 113 public void AddRegion(Scene scene)
@@ -351,7 +359,7 @@ namespace OpenSim.Region.CoreModules.World.Land
351 { 359 {
352 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT) 360 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT)
353 { 361 {
354 if (parcelAvatarIsEntering.IsBannedFromLand(avatar.UUID)) 362 if (parcelAvatarIsEntering.IsEitherBannedOrRestricted(avatar.UUID))
355 { 363 {
356 SendYouAreBannedNotice(avatar); 364 SendYouAreBannedNotice(avatar);
357 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar)); 365 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
@@ -662,7 +670,7 @@ namespace OpenSim.Region.CoreModules.World.Land
662 int x; 670 int x;
663 int y; 671 int y;
664 672
665 if (x_float > Constants.RegionSize || x_float <= 0 || y_float > Constants.RegionSize || y_float <= 0) 673 if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0)
666 return null; 674 return null;
667 675
668 try 676 try
@@ -1005,6 +1013,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1005 //Owner Flag 1013 //Owner Flag
1006 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 1014 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1007 } 1015 }
1016 else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID))
1017 {
1018 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_GROUP);
1019 }
1008 else if (currentParcelBlock.LandData.SalePrice > 0 && 1020 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1009 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || 1021 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1010 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) 1022 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
@@ -1299,7 +1311,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1299 { 1311 {
1300 land.DeedToGroup(groupID); 1312 land.DeedToGroup(groupID);
1301 } 1313 }
1302 1314 EventManagerOnParcelPrimCountTainted();
1303 } 1315 }
1304 1316
1305 1317
@@ -1307,18 +1319,31 @@ namespace OpenSim.Region.CoreModules.World.Land
1307 1319
1308 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1320 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1309 { 1321 {
1310 for (int i = 0; i < data.Count; i++) 1322 lock (m_landList)
1311 { 1323 {
1312 IncomingLandObjectFromStorage(data[i]); 1324 //Remove all the land objects in the sim and then process our new data
1325 foreach (int n in m_landList.Keys)
1326 {
1327 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[n].LandData.GlobalID);
1328 }
1329 m_landIDList.Initialize();
1330 m_landList.Clear();
1331
1332 for (int i = 0; i < data.Count; i++)
1333 {
1334 IncomingLandObjectFromStorage(data[i]);
1335 }
1313 } 1336 }
1314 } 1337 }
1315 1338
1316 public void IncomingLandObjectFromStorage(LandData data) 1339 public void IncomingLandObjectFromStorage(LandData data)
1317 { 1340 {
1341
1318 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1342 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1319 new_land.LandData = data.Copy(); 1343 new_land.LandData = data.Copy();
1320 new_land.SetLandBitmapFromByteArray(); 1344 new_land.SetLandBitmapFromByteArray();
1321 AddLandObject(new_land); 1345 AddLandObject(new_land);
1346 new_land.SendLandUpdateToAvatarsOverMe();
1322 } 1347 }
1323 1348
1324 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) 1349 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
@@ -1591,5 +1616,321 @@ namespace OpenSim.Region.CoreModules.World.Land
1591 1616
1592 UpdateLandObject(localID, land.LandData); 1617 UpdateLandObject(localID, land.LandData);
1593 } 1618 }
1619
1620 public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
1621 {
1622 ILandObject land = null;
1623 List<ILandObject> Land = ((Scene)client.Scene).LandChannel.AllParcels();
1624 foreach (ILandObject landObject in Land)
1625 {
1626 if (landObject.LandData.LocalID == landID)
1627 {
1628 land = landObject;
1629 }
1630 }
1631 land.DeedToGroup(DefaultGodParcelGroup);
1632 land.LandData.Name = DefaultGodParcelName;
1633 land.SendLandUpdateToAvatarsOverMe();
1634 }
1635
1636 private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
1637 {
1638 ScenePresence SP;
1639 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP);
1640 List<SceneObjectGroup> returns = new List<SceneObjectGroup>();
1641 if (SP.UserLevel != 0)
1642 {
1643 if (flags == 0) //All parcels, scripted or not
1644 {
1645 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1646 {
1647 if (e.OwnerID == targetID)
1648 {
1649 returns.Add(e);
1650 }
1651 }
1652 );
1653 }
1654 if (flags == 4) //All parcels, scripted object
1655 {
1656 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1657 {
1658 if (e.OwnerID == targetID)
1659 {
1660 if (e.scriptScore >= 0.01)
1661 {
1662 returns.Add(e);
1663 }
1664 }
1665 }
1666 );
1667 }
1668 if (flags == 4) //not target parcel, scripted object
1669 {
1670 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1671 {
1672 if (e.OwnerID == targetID)
1673 {
1674 ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
1675 if (landobject.LandData.OwnerID != e.OwnerID)
1676 {
1677 if (e.scriptScore >= 0.01)
1678 {
1679 returns.Add(e);
1680 }
1681 }
1682 }
1683 }
1684 );
1685 }
1686 foreach (SceneObjectGroup ol in returns)
1687 {
1688 ReturnObject(ol, client);
1689 }
1690 }
1691 }
1692 public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
1693 {
1694 SceneObjectGroup[] objs = new SceneObjectGroup[1];
1695 objs[0] = obj;
1696 ((Scene)client.Scene).returnObjects(objs, client.AgentId);
1697 }
1698
1699 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1700
1701 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1702 {
1703 ScenePresence targetAvatar = null;
1704 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1705 ScenePresence parcelManager = null;
1706 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1707 System.Threading.Timer Timer;
1708
1709 if (targetAvatar.UserLevel == 0)
1710 {
1711 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1712 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1713 return;
1714 if (flags == 0)
1715 {
1716 targetAvatar.AllowMovement = false;
1717 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1718 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1719 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1720 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1721 Timers.Add(targetAvatar.UUID, Timer);
1722 }
1723 else
1724 {
1725 targetAvatar.AllowMovement = true;
1726 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1727 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1728 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1729 Timers.Remove(targetAvatar.UUID);
1730 Timer.Dispose();
1731 }
1732 }
1733 }
1734 private void OnEndParcelFrozen(object avatar)
1735 {
1736 ScenePresence targetAvatar = (ScenePresence)avatar;
1737 targetAvatar.AllowMovement = true;
1738 System.Threading.Timer Timer;
1739 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1740 Timers.Remove(targetAvatar.UUID);
1741 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1742 }
1743
1744
1745 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1746 {
1747 ScenePresence targetAvatar = null;
1748 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1749 ScenePresence parcelManager = null;
1750 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1751 //Just eject
1752 if (flags == 0)
1753 {
1754 if (targetAvatar.UserLevel == 0)
1755 {
1756 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1757 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1758 return;
1759
1760 Vector3 position = new Vector3(0, 0, 0);
1761 List<ILandObject> allParcels = new List<ILandObject>();
1762 allParcels = AllParcels();
1763 if (allParcels.Count != 1)
1764 {
1765 foreach (ILandObject parcel in allParcels)
1766 {
1767 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1768 {
1769 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1770 {
1771 for (int x = 1; x <= Constants.RegionSize; x += 2)
1772 {
1773 for (int y = 1; y <= Constants.RegionSize; y += 2)
1774 {
1775 if (parcel.ContainsPoint(x, y))
1776 {
1777 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1778 targetAvatar.TeleportWithMomentum(position);
1779 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1780 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1781 return;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 }
1788 }
1789 Vector3 targetVector;
1790 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1791 {
1792 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1793 {
1794 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1795 targetAvatar.TeleportWithMomentum(targetVector);
1796 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1797 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1798 return;
1799 }
1800 else
1801 {
1802 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1803 targetAvatar.TeleportWithMomentum(targetVector);
1804 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1805 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1806 return;
1807 }
1808 }
1809 else
1810 {
1811 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1812 {
1813 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1814 targetAvatar.TeleportWithMomentum(targetVector);
1815 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1816 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1817 return;
1818 }
1819 else
1820 {
1821 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1822 targetAvatar.TeleportWithMomentum(targetVector);
1823 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1824 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1825 return;
1826 }
1827 }
1828 }
1829 }
1830 //Eject and ban
1831 if (flags == 1)
1832 {
1833 if (targetAvatar.UserLevel == 0)
1834 {
1835 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1836 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1837 return;
1838
1839 Vector3 position = new Vector3(0, 0, 0);
1840 List<ILandObject> allParcels = new List<ILandObject>();
1841 allParcels = AllParcels();
1842 if (allParcels.Count != 1)
1843 {
1844 foreach (ILandObject parcel in allParcels)
1845 {
1846 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1847 {
1848 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1849 {
1850 for (int x = 1; x <= Constants.RegionSize; x += 2)
1851 {
1852 for (int y = 1; y <= Constants.RegionSize; y += 2)
1853 {
1854 if (parcel.ContainsPoint(x, y))
1855 {
1856 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1857 targetAvatar.TeleportWithMomentum(position);
1858 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1859 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1860 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1861 entry.AgentID = targetAvatar.UUID;
1862 entry.Flags = AccessList.Ban;
1863 entry.Time = new DateTime();
1864 land.LandData.ParcelAccessList.Add(entry);
1865 return;
1866 }
1867 }
1868 }
1869 }
1870 }
1871 }
1872 }
1873 Vector3 targetVector;
1874 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1875 {
1876 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1877 {
1878 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1879 targetAvatar.TeleportWithMomentum(targetVector);
1880 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1881 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1882 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1883 entry.AgentID = targetAvatar.UUID;
1884 entry.Flags = AccessList.Ban;
1885 entry.Time = new DateTime();
1886 land.LandData.ParcelAccessList.Add(entry);
1887 return;
1888 }
1889 else
1890 {
1891 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1892 targetAvatar.TeleportWithMomentum(targetVector);
1893 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1894 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1895 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1896 entry.AgentID = targetAvatar.UUID;
1897 entry.Flags = AccessList.Ban;
1898 entry.Time = new DateTime();
1899 land.LandData.ParcelAccessList.Add(entry);
1900 return;
1901 }
1902 }
1903 else
1904 {
1905 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1906 {
1907 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1908 targetAvatar.TeleportWithMomentum(targetVector);
1909 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1910 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1911 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1912 entry.AgentID = targetAvatar.UUID;
1913 entry.Flags = AccessList.Ban;
1914 entry.Time = new DateTime();
1915 land.LandData.ParcelAccessList.Add(entry);
1916 return;
1917 }
1918 else
1919 {
1920 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1921 targetAvatar.TeleportWithMomentum(targetVector);
1922 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1923 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1924 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1925 entry.AgentID = targetAvatar.UUID;
1926 entry.Flags = AccessList.Ban;
1927 entry.Time = new DateTime();
1928 land.LandData.ParcelAccessList.Add(entry);
1929 return;
1930 }
1931 }
1932 }
1933 }
1934 }
1594 } 1935 }
1595} 1936}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 3e41c55..f4ebbf0 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -364,6 +364,37 @@ namespace OpenSim.Region.CoreModules.World.Land
364 return false; 364 return false;
365 } 365 }
366 366
367 public bool HasGroupAccess(UUID avatar)
368 {
369 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
370 {
371 ScenePresence sp;
372 if (!m_scene.TryGetScenePresence(avatar, out sp))
373 {
374 IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
375 if (groupsModule == null)
376 return false;
377
378 GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
379 if (membership == null || membership.Length == 0)
380 return false;
381
382 foreach (GroupMembershipData d in membership)
383 {
384 if (d.GroupID == LandData.GroupID)
385 return true;
386 }
387 return false;
388 }
389
390 if (!sp.ControllingClient.IsGroupMember(LandData.GroupID))
391 return false;
392
393 return true;
394 }
395 return false;
396 }
397
367 public bool IsBannedFromLand(UUID avatar) 398 public bool IsBannedFromLand(UUID avatar)
368 { 399 {
369 if (m_scene.Permissions.IsAdministrator(avatar)) 400 if (m_scene.Permissions.IsAdministrator(avatar))
@@ -400,9 +431,13 @@ namespace OpenSim.Region.CoreModules.World.Land
400 return false; 431 return false;
401 }) == -1 && LandData.OwnerID != avatar) 432 }) == -1 && LandData.OwnerID != avatar)
402 { 433 {
403 return true; 434 if (!HasGroupAccess(avatar))
435 {
436 return true;
437 }
404 } 438 }
405 } 439 }
440
406 return false; 441 return false;
407 } 442 }
408 443
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 364dd6c..f9b2384 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -362,7 +362,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
362 362
363 public string Name 363 public string Name
364 { 364 {
365 get { return "PermissionsModule"; } 365 get { return "DefaultPermissionsModule"; }
366 } 366 }
367 367
368 public bool IsSharedModule 368 public bool IsSharedModule
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index c65aa6a..2e82e7e 100644
--- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
@@ -28,6 +28,8 @@
28using System; 28using System;
29using System.Reflection; 29using System.Reflection;
30using System.Timers; 30using System.Timers;
31using System.IO;
32using System.Diagnostics;
31using System.Threading; 33using System.Threading;
32using System.Collections.Generic; 34using System.Collections.Generic;
33using log4net; 35using log4net;
@@ -56,13 +58,23 @@ namespace OpenSim.Region.CoreModules.World.Region
56 protected UUID m_Initiator; 58 protected UUID m_Initiator;
57 protected bool m_Notice = false; 59 protected bool m_Notice = false;
58 protected IDialogModule m_DialogModule = null; 60 protected IDialogModule m_DialogModule = null;
61 protected string m_MarkerPath = String.Empty;
59 62
60 public void Initialise(IConfigSource config) 63 public void Initialise(IConfigSource config)
61 { 64 {
65 IConfig restartConfig = config.Configs["RestartModule"];
66 if (restartConfig != null)
67 {
68 m_MarkerPath = restartConfig.GetString("MarkerPath", String.Empty);
69 }
62 } 70 }
63 71
64 public void AddRegion(Scene scene) 72 public void AddRegion(Scene scene)
65 { 73 {
74 if (m_MarkerPath != String.Empty)
75 File.Delete(Path.Combine(m_MarkerPath,
76 scene.RegionInfo.RegionID.ToString()));
77
66 m_Scene = scene; 78 m_Scene = scene;
67 scene.RegisterModuleInterface<IRestartModule>(this); 79 scene.RegisterModuleInterface<IRestartModule>(this);
68 MainConsole.Instance.Commands.AddCommand("RestartModule", 80 MainConsole.Instance.Commands.AddCommand("RestartModule",
@@ -114,6 +126,7 @@ namespace OpenSim.Region.CoreModules.World.Region
114 126
115 if (alerts == null) 127 if (alerts == null)
116 { 128 {
129 CreateMarkerFile();
117 m_Scene.RestartNow(); 130 m_Scene.RestartNow();
118 return; 131 return;
119 } 132 }
@@ -127,6 +140,7 @@ namespace OpenSim.Region.CoreModules.World.Region
127 140
128 if (m_Alerts[0] == 0) 141 if (m_Alerts[0] == 0)
129 { 142 {
143 CreateMarkerFile();
130 m_Scene.RestartNow(); 144 m_Scene.RestartNow();
131 return; 145 return;
132 } 146 }
@@ -140,6 +154,7 @@ namespace OpenSim.Region.CoreModules.World.Region
140 { 154 {
141 if (m_Alerts.Count == 0 || m_Alerts[0] == 0) 155 if (m_Alerts.Count == 0 || m_Alerts[0] == 0)
142 { 156 {
157 CreateMarkerFile();
143 m_Scene.RestartNow(); 158 m_Scene.RestartNow();
144 return 0; 159 return 0;
145 } 160 }
@@ -259,5 +274,25 @@ namespace OpenSim.Region.CoreModules.World.Region
259 274
260 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice); 275 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
261 } 276 }
277
278 protected void CreateMarkerFile()
279 {
280 if (m_MarkerPath == String.Empty)
281 return;
282
283 string path = Path.Combine(m_MarkerPath, m_Scene.RegionInfo.RegionID.ToString());
284 try
285 {
286 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
287 FileStream fs = File.Create(path);
288 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
289 Byte[] buf = enc.GetBytes(pidstring);
290 fs.Write(buf, 0, buf.Length);
291 fs.Close();
292 }
293 catch (Exception)
294 {
295 }
296 }
262 } 297 }
263} 298}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 25d73c2..4611352 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -549,6 +549,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
549 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); 549 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
550 m_scene.SaveTerrain(); 550 m_scene.SaveTerrain();
551 551
552 m_scene.EventManager.TriggerTerrainUpdate();
553
552 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. 554 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
553 //m_scene.CreateTerrainTexture(true); 555 //m_scene.CreateTerrainTexture(true);
554 } 556 }
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index bdd1a0b..334dcb0 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -86,9 +86,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
86 86
87 private void OnMapNameRequest(IClientAPI remoteClient, string mapName) 87 private void OnMapNameRequest(IClientAPI remoteClient, string mapName)
88 { 88 {
89 if (mapName.Length < 3) 89 if (mapName.Length < 2)
90 { 90 {
91 remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); 91 remoteClient.SendAlertMessage("Use a search string with at least 2 characters");
92 return; 92 return;
93 } 93 }
94 94
diff --git a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs b/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
index e951bef..7a0ce51 100644
--- a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
+++ b/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Collections.Generic;
28using OpenMetaverse; 29using OpenMetaverse;
29using OpenSim.Framework; 30using OpenSim.Framework;
30using OpenSim.Region.Framework.Scenes; 31using OpenSim.Region.Framework.Scenes;
@@ -110,7 +111,7 @@ namespace OpenSim.Region.Examples.SimpleModule
110 { 111 {
111 m_parts.Remove(part.UUID); 112 m_parts.Remove(part.UUID);
112 113
113 remoteClient.SendKillObject(m_regionHandle, part.LocalId); 114 remoteClient.SendKillObject(m_regionHandle, new List<uint>() { part.LocalId} );
114 remoteClient.AddMoney(1); 115 remoteClient.AddMoney(1);
115 remoteClient.SendChatMessage("Poof!", 1, AbsolutePosition, "Party Party", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); 116 remoteClient.SendChatMessage("Poof!", 1, AbsolutePosition, "Party Party", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
116 } 117 }
@@ -121,7 +122,7 @@ namespace OpenSim.Region.Examples.SimpleModule
121 { 122 {
122 m_parts.Remove(m_rootPart.UUID); 123 m_parts.Remove(m_rootPart.UUID);
123 m_scene.DeleteSceneObject(this, false); 124 m_scene.DeleteSceneObject(this, false);
124 remoteClient.SendKillObject(m_regionHandle, m_rootPart.LocalId); 125 remoteClient.SendKillObject(m_regionHandle, new List<uint>() { m_rootPart.LocalId });
125 remoteClient.AddMoney(50); 126 remoteClient.AddMoney(50);
126 remoteClient.SendChatMessage("KABLAM!!!", 1, AbsolutePosition, "Groupie Groupie", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); 127 remoteClient.SendChatMessage("KABLAM!!!", 1, AbsolutePosition, "Groupie Groupie", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
127 } 128 }
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 41d6628..5151bf0 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -79,7 +79,7 @@ namespace OpenSim.Region.Examples.SimpleModule
79 public event DisconnectUser OnDisconnectUser; 79 public event DisconnectUser OnDisconnectUser;
80 public event RequestAvatarProperties OnRequestAvatarProperties; 80 public event RequestAvatarProperties OnRequestAvatarProperties;
81 public event SetAlwaysRun OnSetAlwaysRun; 81 public event SetAlwaysRun OnSetAlwaysRun;
82 82 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
83 public event DeRezObject OnDeRezObject; 83 public event DeRezObject OnDeRezObject;
84 public event Action<IClientAPI> OnRegionHandShakeReply; 84 public event Action<IClientAPI> OnRegionHandShakeReply;
85 public event GenericCall1 OnRequestWearables; 85 public event GenericCall1 OnRequestWearables;
@@ -429,7 +429,7 @@ namespace OpenSim.Region.Examples.SimpleModule
429 429
430 } 430 }
431 431
432 public virtual void SendKillObject(ulong regionHandle, uint localID) 432 public virtual void SendKillObject(ulong regionHandle, List<uint> localID)
433 { 433 {
434 } 434 }
435 435
@@ -833,6 +833,11 @@ namespace OpenSim.Region.Examples.SimpleModule
833 833
834 public void Close() 834 public void Close()
835 { 835 {
836 Close(true);
837 }
838
839 public void Close(bool sendStop)
840 {
836 } 841 }
837 842
838 public void Start() 843 public void Start()
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 6cc64c6..788f42b 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Xml;
29using OpenMetaverse; 30using OpenMetaverse;
30using OpenMetaverse.Packets; 31using OpenMetaverse.Packets;
31using OpenSim.Framework; 32using OpenSim.Framework;
@@ -82,6 +83,10 @@ namespace OpenSim.Region.Framework.Interfaces
82 UUID RezSingleAttachmentFromInventory( 83 UUID RezSingleAttachmentFromInventory(
83 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); 84 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus);
84 85
86 // Same as above, but also load script states from a separate doc
87 UUID RezSingleAttachmentFromInventory(
88 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc);
89
85 /// <summary> 90 /// <summary>
86 /// Rez multiple attachments from a user's inventory 91 /// Rez multiple attachments from a user's inventory
87 /// </summary> 92 /// </summary>
@@ -113,18 +118,15 @@ namespace OpenSim.Region.Framework.Interfaces
113 /// <summary> 118 /// <summary>
114 /// Update the user inventory to show a detach. 119 /// Update the user inventory to show a detach.
115 /// </summary> 120 /// </summary>
116 /// <param name="itemID">/param> 121 /// <param name="itemID">
117 /// <param name="remoteClient"></param> 122 /// A <see cref="UUID"/>
123 /// </param>
124 /// <param name="remoteClient">
125 /// A <see cref="IClientAPI"/>
126 /// </param>
118 void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient); 127 void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient);
119 128
120 /// <summary> 129 /// <summary>
121 /// Update the position of an attachment.
122 /// </summary>
123 /// <param name="sog"></param>
124 /// <param name="pos"></param>
125 void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos);
126
127 /// <summary>
128 /// Update the user inventory with a changed attachment 130 /// Update the user inventory with a changed attachment
129 /// </summary> 131 /// </summary>
130 /// <param name="remoteClient"> 132 /// <param name="remoteClient">
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
index 15060fd..4b17b9a 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
@@ -115,6 +115,8 @@ namespace OpenSim.Region.Framework.Interfaces
115 /// <param name="stateSource"></param> 115 /// <param name="stateSource"></param>
116 void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); 116 void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource);
117 117
118 ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource);
119
118 /// <summary> 120 /// <summary>
119 /// Stop a script which is in this prim's inventory. 121 /// Stop a script which is in this prim's inventory.
120 /// </summary> 122 /// </summary>
@@ -229,5 +231,6 @@ namespace OpenSim.Region.Framework.Interfaces
229 /// A <see cref="Dictionary`2"/> 231 /// A <see cref="Dictionary`2"/>
230 /// </returns> 232 /// </returns>
231 Dictionary<UUID, string> GetScriptStates(); 233 Dictionary<UUID, string> GetScriptStates();
234 Dictionary<UUID, string> GetScriptStates(bool oldIDs);
232 } 235 }
233} 236}
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
index e8738c4..45ca5c5 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
@@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Interfaces
40 void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, 40 void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position,
41 Vector3 lookAt, uint teleportFlags); 41 Vector3 lookAt, uint teleportFlags);
42 42
43 void TeleportHome(UUID id, IClientAPI client); 43 bool TeleportHome(UUID id, IClientAPI client);
44 44
45 void Cross(ScenePresence agent, bool isFlying); 45 void Cross(ScenePresence agent, bool isFlying);
46 46
diff --git a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs b/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
index 2d6287f..67a500f 100644
--- a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
+++ b/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
@@ -68,6 +68,14 @@ namespace OpenSim.Region.Framework.Interfaces
68 bool SendReleaseAgent(ulong regionHandle, UUID id, string uri); 68 bool SendReleaseAgent(ulong regionHandle, UUID id, string uri);
69 69
70 /// <summary> 70 /// <summary>
71 /// Close chid agent.
72 /// </summary>
73 /// <param name="regionHandle"></param>
74 /// <param name="id"></param>
75 /// <returns></returns>
76 bool SendCloseChildAgent(ulong regionHandle, UUID id);
77
78 /// <summary>
71 /// Close agent. 79 /// Close agent.
72 /// </summary> 80 /// </summary>
73 /// <param name="regionHandle"></param> 81 /// <param name="regionHandle"></param>
diff --git a/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs
new file mode 100644
index 0000000..e01f649
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs
@@ -0,0 +1,27 @@
1///////////////////////////////////////////////////////////////////
2//
3// (c) Careminster LImited, Melanie Thielker and the Meta7 Team
4//
5// This file is not open source. All rights reserved
6// Mod 2
7
8using OpenSim.Region.Framework.Scenes;
9
10public interface ISnmpModule
11{
12 void Trap(int code, string Message, Scene scene);
13 void Critical(string Message, Scene scene);
14 void Warning(string Message, Scene scene);
15 void Major(string Message, Scene scene);
16 void ColdStart(int step , Scene scene);
17 void Shutdown(int step , Scene scene);
18 //
19 // Node Start/stop events
20 //
21 void LinkUp(Scene scene);
22 void LinkDown(Scene scene);
23 void BootInfo(string data, Scene scene);
24 void trapDebug(string Module,string data, Scene scene);
25 void trapXMRE(int data, string Message, Scene scene);
26
27}
diff --git a/OpenSim/Region/Framework/ModuleLoader.cs b/OpenSim/Region/Framework/ModuleLoader.cs
index 23be9c2..69ba2042 100644
--- a/OpenSim/Region/Framework/ModuleLoader.cs
+++ b/OpenSim/Region/Framework/ModuleLoader.cs
@@ -226,7 +226,8 @@ namespace OpenSim.Region.Framework
226 "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e); 226 "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e);
227 227
228 // justincc: Right now this is fatal to really get the user's attention 228 // justincc: Right now this is fatal to really get the user's attention
229 throw e; 229 // TomMeta: WTF? No, how about we /don't/ throw a fatal exception when there's no need to?
230 //throw e;
230 } 231 }
231 } 232 }
232 233
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 4865481..9c103cb 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -53,11 +53,17 @@ namespace OpenSim.Region.Framework.Scenes.Animation
53 { 53 {
54 get { return m_movementAnimation; } 54 get { return m_movementAnimation; }
55 } 55 }
56 protected string m_movementAnimation = "DEFAULT"; 56 // protected string m_movementAnimation = "DEFAULT"; //KF: 'DEFAULT' does not exist!
57 57 protected string m_movementAnimation = "CROUCH"; //KF: CROUCH ensures reliable Av Anim. init.
58 private int m_animTickFall; 58 private int m_animTickFall;
59 private int m_animTickJump; 59// private int m_animTickJump;
60 60 public int m_animTickJump; // ScenePresence has to see this to control +Z force
61 public bool m_jumping = false; // Add for jumping
62 public float m_jumpVelocity = 0f; // Add for jumping
63 private int m_landing = 0; // Add for jumping
64 public bool m_falling = false; // Add for falling
65 private float m_fallHeight; // Add for falling
66
61 /// <value> 67 /// <value>
62 /// The scene presence that this animator applies to 68 /// The scene presence that this animator applies to
63 /// </value> 69 /// </value>
@@ -114,7 +120,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
114 120
115 public void ResetAnimations() 121 public void ResetAnimations()
116 { 122 {
123Console.WriteLine("ResetA.............");
117 m_animations.Clear(); 124 m_animations.Clear();
125TrySetMovementAnimation("STAND");
118 } 126 }
119 127
120 /// <summary> 128 /// <summary>
@@ -123,8 +131,6 @@ namespace OpenSim.Region.Framework.Scenes.Animation
123 /// </summary> 131 /// </summary>
124 public void TrySetMovementAnimation(string anim) 132 public void TrySetMovementAnimation(string anim)
125 { 133 {
126 //m_log.DebugFormat("Updating movement animation to {0}", anim);
127
128 if (!m_scenePresence.IsChildAgent) 134 if (!m_scenePresence.IsChildAgent)
129 { 135 {
130 if (m_animations.TrySetDefaultAnimation( 136 if (m_animations.TrySetDefaultAnimation(
@@ -142,14 +148,14 @@ namespace OpenSim.Region.Framework.Scenes.Animation
142 /// </summary> 148 /// </summary>
143 public string GetMovementAnimation() 149 public string GetMovementAnimation()
144 { 150 {
145 const float FALL_DELAY = 0.33f; 151//Console.WriteLine("GMA-------"); //##
146 const float PREJUMP_DELAY = 0.25f; 152//#@ const float FALL_DELAY = 0.33f;
147 153 const float FALL_DELAY = 800f; //## mS
154//rm for jumping const float PREJUMP_DELAY = 0.25f;
155 const float PREJUMP_DELAY = 200f; // mS add for jumping
156 const float JUMP_PERIOD = 800f; // mS add for jumping
148 #region Inputs 157 #region Inputs
149 if (m_scenePresence.SitGround) 158
150 {
151 return "SIT_GROUND_CONSTRAINED";
152 }
153 AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; 159 AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags;
154 PhysicsActor actor = m_scenePresence.PhysicsActor; 160 PhysicsActor actor = m_scenePresence.PhysicsActor;
155 161
@@ -159,11 +165,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
159 Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); 165 Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix);
160 166
161 // Check control flags 167 // Check control flags
162 bool heldForward = 168 bool heldForward = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS);
163 (((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) || ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS)); 169 bool heldBack = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG);
164 bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; 170 bool heldLeft = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS);
165 bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; 171 bool heldRight = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG);
166 bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG;
167 //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; 172 //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT;
168 //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; 173 //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT;
169 bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; 174 bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS;
@@ -182,8 +187,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
182 187
183 // Is the avatar trying to move? 188 // Is the avatar trying to move?
184// bool moving = (move != Vector3.Zero); 189// bool moving = (move != Vector3.Zero);
185 bool jumping = m_animTickJump != 0; 190// rm for jumping bool jumping = m_animTickJump != 0;
186
187 #endregion Inputs 191 #endregion Inputs
188 192
189 #region Flying 193 #region Flying
@@ -192,6 +196,11 @@ namespace OpenSim.Region.Framework.Scenes.Animation
192 { 196 {
193 m_animTickFall = 0; 197 m_animTickFall = 0;
194 m_animTickJump = 0; 198 m_animTickJump = 0;
199 m_jumping = false; //add for jumping
200 m_falling = true; //add for falling
201 m_jumpVelocity = 0f; //add for jumping
202 actor.Selected = false; //add for jumping flag
203 m_fallHeight = actor.Position.Z; // save latest flying height
195 204
196 if (move.X != 0f || move.Y != 0f) 205 if (move.X != 0f || move.Y != 0f)
197 { 206 {
@@ -203,8 +212,11 @@ namespace OpenSim.Region.Framework.Scenes.Animation
203 } 212 }
204 else if (move.Z < 0f) 213 else if (move.Z < 0f)
205 { 214 {
206 if (actor != null && actor.IsColliding) 215 if (actor != null && actor.IsColliding)
216 { //##
217//Console.WriteLine("LAND FLYING"); // ##
207 return "LAND"; 218 return "LAND";
219 } //#
208 else 220 else
209 return "HOVER_DOWN"; 221 return "HOVER_DOWN";
210 } 222 }
@@ -218,48 +230,127 @@ namespace OpenSim.Region.Framework.Scenes.Animation
218 230
219 #region Falling/Floating/Landing 231 #region Falling/Floating/Landing
220 232
221 if (actor == null || !actor.IsColliding) 233// rm for jumping if (actor == null || !actor.IsColliding)
234 if ((actor == null || !actor.IsColliding) && !m_jumping) // add for jumping
222 { 235 {
223 float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; 236// rm float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
237 float fallElapsed = (float)(Environment.TickCount - m_animTickFall); // add, in mS
224 float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f; 238 float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f;
239//Console.WriteLine("falling t={0} v={1}", fallElapsed, fallVelocity); //##
240
241// rm for fall if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f))
242 if (!m_jumping && (fallVelocity < -3.0f) ) m_falling = true; // add for falling and jumping
225 243
226 if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f)) 244 if (m_animTickFall == 0 || (fallVelocity >= 0.0f)) // add for jumping
245 // not falling yet or going up
227 { 246 {
228 // Just started falling 247 // reset start of fall time
229 m_animTickFall = Environment.TickCount; 248 m_animTickFall = Environment.TickCount;
230 } 249 }
231 else if (!jumping && fallElapsed > FALL_DELAY) 250// else if (!jumping && fallElapsed > FALL_DELAY)
251 else if (!m_jumping && (fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f) && (m_scenePresence.m_wasFlying)) // add for falling and jumping
232 { 252 {
233 // Falling long enough to trigger the animation 253 // Falling long enough to trigger the animation
254//Console.WriteLine("FALLDOWN"); //##
234 return "FALLDOWN"; 255 return "FALLDOWN";
235 } 256 }
236 else if (m_animTickJump == -1)
237 {
238 m_animTickJump = 0;
239 return "STAND";
240 }
241 257
242 return m_movementAnimation; 258 return m_movementAnimation;
243 } 259 }
244 260
245 #endregion Falling/Floating/Landing 261 #endregion Falling/Floating/Landing
246 262
263
264 #region Jumping // section added for jumping...
265
266 int jumptime;
267 jumptime = Environment.TickCount - m_animTickJump;
268
269
270 if ((move.Z > 0f) && (!m_jumping))
271 {
272//Console.WriteLine("PJ {0}", jumptime); //##
273 // Start jumping, prejump
274 m_animTickFall = 0;
275 m_jumping = true;
276 m_falling = false;
277 actor.Selected = true; // borrowed for jmping flag
278 m_animTickJump = Environment.TickCount;
279 m_jumpVelocity = 0.35f;
280 return "PREJUMP";
281 }
282
283 if(m_jumping)
284 {
285 if ( (jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding)
286 {
287//Console.WriteLine("LA {0}", jumptime); //##
288 // end jumping
289 m_jumping = false;
290 m_falling = false;
291 actor.Selected = false; // borrowed for jumping flag
292 m_jumpVelocity = 0f;
293 m_animTickFall = Environment.TickCount;
294 return "LAND";
295 }
296 else if (jumptime > JUMP_PERIOD)
297 {
298//Console.WriteLine("JD {0}", jumptime); //##
299 // jump down
300 m_jumpVelocity = 0f;
301 return "JUMP";
302 }
303 else if (jumptime > PREJUMP_DELAY)
304 {
305//Console.WriteLine("JU {0}", jumptime); //##
306 // jump up
307 m_jumping = true;
308 m_jumpVelocity = 10f;
309 return "JUMP";
310 }
311 }
312
313 #endregion Jumping // end added section
314
247 #region Ground Movement 315 #region Ground Movement
248 316
249 if (m_movementAnimation == "FALLDOWN") 317 if (m_movementAnimation == "FALLDOWN")
250 { 318 {
319 m_falling = false;
251 m_animTickFall = Environment.TickCount; 320 m_animTickFall = Environment.TickCount;
252
253 // TODO: SOFT_LAND support 321 // TODO: SOFT_LAND support
254 return "LAND"; 322 float fallHeight = m_fallHeight - actor.Position.Z;
323//Console.WriteLine("Hit from {0}", fallHeight); //##
324 if (fallHeight > 15.0f) // add for falling
325 return "STANDUP";
326 else if (fallHeight > 8.0f) // add for falling
327 return "SOFT_LAND"; // add for falling
328 else // add for falling
329 return "LAND"; // add for falling
255 } 330 }
256 else if (m_movementAnimation == "LAND") 331// rm jumping float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
332// rm jumping if ((m_animTickFall != 0) && (landElapsed <= FALL_DELAY))
333// rm for landing return "LAND";
334 else if ((m_movementAnimation == "LAND") || (m_movementAnimation == "SOFT_LAND") || (m_movementAnimation == "STANDUP"))
257 { 335 {
258 float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; 336 int landElapsed = Environment.TickCount - m_animTickFall; // add for jumping
259 if ((m_animTickFall != 0) && (landElapsed <= FALL_DELAY)) 337 int limit = 1000; // add for jumping
260 return "LAND"; 338 if(m_movementAnimation == "LAND") limit = 350; // add for jumping
261 } 339 // NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client
262 340
341 if ((m_animTickFall != 0) && (landElapsed <= limit)) // add for jumping
342 {
343//Console.WriteLine("Lelapse {0}", m_movementAnimation); //##
344 return m_movementAnimation;
345 }
346 else
347 {
348//Console.WriteLine("end/STAND"); //##
349 m_fallHeight = actor.Position.Z; // save latest flying height
350 return "STAND";
351 }
352 }
353/* This section removed, replaced by jumping section
263 m_animTickFall = 0; 354 m_animTickFall = 0;
264 355
265 if (move.Z > 0f) 356 if (move.Z > 0f)
@@ -271,7 +362,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
271 m_animTickJump = Environment.TickCount; 362 m_animTickJump = Environment.TickCount;
272 return "PREJUMP"; 363 return "PREJUMP";
273 } 364 }
274 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 1000.0f) 365 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 800.0f)
275 { 366 {
276 // Start actual jump 367 // Start actual jump
277 if (m_animTickJump == -1) 368 if (m_animTickJump == -1)
@@ -284,37 +375,40 @@ namespace OpenSim.Region.Framework.Scenes.Animation
284 m_animTickJump = -1; 375 m_animTickJump = -1;
285 return "JUMP"; 376 return "JUMP";
286 } 377 }
287 else
288 return "JUMP";
289 } 378 }
290 else 379 else
291 { 380 {
292 // Not jumping 381 // Not jumping
293 m_animTickJump = 0; 382 m_animTickJump = 0;
294 383 */
295 if (move.X != 0f || move.Y != 0f) 384 // next section moved outside paren. and realigned for jumping
296 { 385 if (move.X != 0f || move.Y != 0f)
297 // Walking / crouchwalking / running 386 {
298 if (move.Z < 0f) 387 m_fallHeight = actor.Position.Z; // save latest flying height
299 return "CROUCHWALK"; 388 m_falling = false; // Add for falling
300 else if (m_scenePresence.SetAlwaysRun) 389 // Walking / crouchwalking / running
301 return "RUN"; 390 if (move.Z < 0f)
302 else 391 return "CROUCHWALK";
303 return "WALK"; 392 else if (m_scenePresence.SetAlwaysRun)
304 } 393 return "RUN";
305 else 394 else
306 { 395 return "WALK";
307 // Not walking
308 if (move.Z < 0f)
309 return "CROUCH";
310 else
311 return "STAND";
312 }
313 } 396 }
314 397// rm for jumping else
398 else if (!m_jumping) // add for jumping
399 {
400 m_falling = false; // Add for falling
401 // Not walking
402 if (move.Z < 0f)
403 return "CROUCH";
404 else
405 return "STAND";
406 }
407 // end section realign for jumping
315 #endregion Ground Movement 408 #endregion Ground Movement
316 409
317 //return m_movementAnimation; 410 m_falling = false; // Add for falling
411 return m_movementAnimation;
318 } 412 }
319 413
320 /// <summary> 414 /// <summary>
@@ -323,7 +417,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation
323 public void UpdateMovementAnimations() 417 public void UpdateMovementAnimations()
324 { 418 {
325 m_movementAnimation = GetMovementAnimation(); 419 m_movementAnimation = GetMovementAnimation();
326 TrySetMovementAnimation(m_movementAnimation); 420/* if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump)
421 {
422 // This was the previous behavior before PREJUMP
423 TrySetMovementAnimation("JUMP");
424 }
425 else
426 { removed for jumping */
427 TrySetMovementAnimation(m_movementAnimation);
428// rm for jumping }
327 } 429 }
328 430
329 public UUID[] GetAnimationArray() 431 public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
index 64567db..a8d24fd 100644
--- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
+++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -104,8 +104,15 @@ namespace OpenSim.Region.Framework.Scenes
104 // better than losing the object for now. 104 // better than losing the object for now.
105 if (permissionToDelete) 105 if (permissionToDelete)
106 { 106 {
107 List<uint> killIDs = new List<uint>();
108
107 foreach (SceneObjectGroup g in objectGroups) 109 foreach (SceneObjectGroup g in objectGroups)
110 {
111 killIDs.Add(g.LocalId);
108 g.DeleteGroupFromScene(false); 112 g.DeleteGroupFromScene(false);
113 }
114
115 m_scene.SendKillObject(killIDs);
109 } 116 }
110 } 117 }
111 118
@@ -137,7 +144,7 @@ namespace OpenSim.Region.Framework.Scenes
137 x = m_inventoryDeletes.Dequeue(); 144 x = m_inventoryDeletes.Dequeue();
138 145
139 m_log.DebugFormat( 146 m_log.DebugFormat(
140 "[ASYNC DELETER]: Sending object to user's inventory, {0} item(s) remaining.", left); 147 "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", left, x.action, x.objectGroups.Count);
141 148
142 try 149 try
143 { 150 {
@@ -177,4 +184,4 @@ namespace OpenSim.Region.Framework.Scenes
177 return false; 184 return false;
178 } 185 }
179 } 186 }
180} \ No newline at end of file 187}
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index c321a15..f24c53c 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;
@@ -757,6 +761,26 @@ namespace OpenSim.Region.Framework.Scenes
757 } 761 }
758 } 762 }
759 } 763 }
764 public void TriggerTerrainUpdate()
765 {
766 OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate;
767 if (handlerTerrainUpdate != null)
768 {
769 foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList())
770 {
771 try
772 {
773 d();
774 }
775 catch (Exception e)
776 {
777 m_log.ErrorFormat(
778 "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}",
779 e.Message, e.StackTrace);
780 }
781 }
782 }
783 }
760 784
761 public void TriggerTerrainTick() 785 public void TriggerTerrainTick()
762 { 786 {
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index f9599f5..cde8d3f 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -167,6 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
167 167
168 private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) 168 private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
169 { 169 {
170 if (entity == null) return double.NaN;
170 ScenePresence presence = m_scene.GetScenePresence(client.AgentId); 171 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
171 if (presence != null) 172 if (presence != null)
172 { 173 {
@@ -224,22 +225,16 @@ namespace OpenSim.Region.Framework.Scenes
224 if (entity == null) 225 if (entity == null)
225 return double.NaN; 226 return double.NaN;
226 227
227 // Use group position for child prims 228 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
228 Vector3 entityPos = entity.AbsolutePosition; 229 if (presence != null)
229 if (entity is SceneObjectPart)
230 { 230 {
231 SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; 231 // Use group position for child prims
232 if (group != null) 232 Vector3 entityPos;
233 entityPos = group.AbsolutePosition; 233 if (entity is SceneObjectPart)
234 entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
234 else 235 else
235 entityPos = entity.AbsolutePosition; 236 entityPos = entity.AbsolutePosition;
236 }
237 else
238 entityPos = entity.AbsolutePosition;
239 237
240 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
241 if (presence != null)
242 {
243 if (!presence.IsChildAgent) 238 if (!presence.IsChildAgent)
244 { 239 {
245 if (entity is ScenePresence) 240 if (entity is ScenePresence)
@@ -259,12 +254,19 @@ namespace OpenSim.Region.Framework.Scenes
259 254
260 if (entity is SceneObjectPart) 255 if (entity is SceneObjectPart)
261 { 256 {
262 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
263 if (physActor == null || !physActor.IsPhysical)
264 priority += 100;
265
266 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) 257 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
258 {
267 priority = 1.0; 259 priority = 1.0;
260 }
261 else
262 {
263 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
264 if (physActor == null || !physActor.IsPhysical)
265 priority += 100;
266 }
267
268 if (((SceneObjectPart)entity).ParentGroup.RootPart != (SceneObjectPart)entity)
269 priority +=1;
268 } 270 }
269 return priority; 271 return priority;
270 } 272 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index dc2ce48..682c36d 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -99,34 +99,22 @@ namespace OpenSim.Region.Framework.Scenes
99 /// <param name="item"></param> 99 /// <param name="item"></param>
100 public bool AddInventoryItem(InventoryItemBase item) 100 public bool AddInventoryItem(InventoryItemBase item)
101 { 101 {
102 if (UUID.Zero == item.Folder) 102 InventoryFolderBase folder;
103
104 if (item.Folder == UUID.Zero)
103 { 105 {
104 InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType); 106 folder = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
105 if (f != null) 107 if (folder == null)
106 {
107// m_log.DebugFormat(
108// "[LOCAL INVENTORY SERVICES CONNECTOR]: Found folder {0} type {1} for item {2}",
109// f.Name, (AssetType)f.Type, item.Name);
110
111 item.Folder = f.ID;
112 }
113 else
114 { 108 {
115 f = InventoryService.GetRootFolder(item.Owner); 109 folder = InventoryService.GetRootFolder(item.Owner);
116 if (f != null) 110
117 { 111 if (folder == null)
118 item.Folder = f.ID;
119 }
120 else
121 {
122 m_log.WarnFormat(
123 "[AGENT INVENTORY]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
124 item.Owner, item.Name);
125 return false; 112 return false;
126 }
127 } 113 }
114
115 item.Folder = folder.ID;
128 } 116 }
129 117
130 if (InventoryService.AddItem(item)) 118 if (InventoryService.AddItem(item))
131 { 119 {
132 int userlevel = 0; 120 int userlevel = 0;
@@ -252,8 +240,7 @@ namespace OpenSim.Region.Framework.Scenes
252 240
253 // Update item with new asset 241 // Update item with new asset
254 item.AssetID = asset.FullID; 242 item.AssetID = asset.FullID;
255 if (group.UpdateInventoryItem(item)) 243 group.UpdateInventoryItem(item);
256 remoteClient.SendAgentAlertMessage("Script saved", false);
257 244
258 part.GetProperties(remoteClient); 245 part.GetProperties(remoteClient);
259 246
@@ -264,12 +251,7 @@ namespace OpenSim.Region.Framework.Scenes
264 { 251 {
265 // Needs to determine which engine was running it and use that 252 // Needs to determine which engine was running it and use that
266 // 253 //
267 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); 254 errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 0);
268 errors = part.Inventory.GetScriptErrors(item.ItemID);
269 }
270 else
271 {
272 remoteClient.SendAgentAlertMessage("Script saved", false);
273 } 255 }
274 part.ParentGroup.ResumeScripts(); 256 part.ParentGroup.ResumeScripts();
275 return errors; 257 return errors;
@@ -688,6 +670,8 @@ namespace OpenSim.Region.Framework.Scenes
688 return; 670 return;
689 } 671 }
690 672
673 if (newName == null) newName = item.Name;
674
691 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 675 AssetBase asset = AssetService.Get(item.AssetID.ToString());
692 676
693 if (asset != null) 677 if (asset != null)
@@ -741,6 +725,24 @@ namespace OpenSim.Region.Framework.Scenes
741 } 725 }
742 726
743 /// <summary> 727 /// <summary>
728 /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
729 /// </summary>
730 public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
731 {
732 List<InventoryItemBase> moveitems = new List<InventoryItemBase>();
733 foreach (InventoryItemBase b in items)
734 {
735 CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
736 InventoryItemBase n = InventoryService.GetItem(b);
737 n.Folder = destfolder;
738 moveitems.Add(n);
739 remoteClient.SendInventoryItemCreateUpdate(n, 0);
740 }
741
742 MoveInventoryItem(remoteClient, moveitems);
743 }
744
745 /// <summary>
744 /// Move an item within the agent's inventory. 746 /// Move an item within the agent's inventory.
745 /// </summary> 747 /// </summary>
746 /// <param name="remoteClient"></param> 748 /// <param name="remoteClient"></param>
@@ -973,8 +975,12 @@ namespace OpenSim.Region.Framework.Scenes
973 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID) 975 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
974 { 976 {
975 SceneObjectPart part = GetSceneObjectPart(localID); 977 SceneObjectPart part = GetSceneObjectPart(localID);
976 SceneObjectGroup group = part.ParentGroup; 978 SceneObjectGroup group = null;
977 if (group != null) 979 if (part != null)
980 {
981 group = part.ParentGroup;
982 }
983 if (part != null && group != null)
978 { 984 {
979 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)) 985 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
980 return; 986 return;
@@ -1423,13 +1429,6 @@ namespace OpenSim.Region.Framework.Scenes
1423 { 1429 {
1424 agentTransactions.HandleTaskItemUpdateFromTransaction( 1430 agentTransactions.HandleTaskItemUpdateFromTransaction(
1425 remoteClient, part, transactionID, currentItem); 1431 remoteClient, part, transactionID, currentItem);
1426
1427 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1428 remoteClient.SendAgentAlertMessage("Notecard saved", false);
1429 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1430 remoteClient.SendAgentAlertMessage("Script saved", false);
1431 else
1432 remoteClient.SendAgentAlertMessage("Item saved", false);
1433 } 1432 }
1434 1433
1435 // Base ALWAYS has move 1434 // Base ALWAYS has move
@@ -1547,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes
1547 return; 1546 return;
1548 1547
1549 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1548 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
1550 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1549 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"),
1551 remoteClient.AgentId); 1550 remoteClient.AgentId);
1552 AssetService.Store(asset); 1551 AssetService.Store(asset);
1553 1552
@@ -1700,23 +1699,32 @@ namespace OpenSim.Region.Framework.Scenes
1700 // build a list of eligible objects 1699 // build a list of eligible objects
1701 List<uint> deleteIDs = new List<uint>(); 1700 List<uint> deleteIDs = new List<uint>();
1702 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>(); 1701 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
1703 1702 List<SceneObjectGroup> takeGroups = new List<SceneObjectGroup>();
1704 // Start with true for both, then remove the flags if objects
1705 // that we can't derez are part of the selection
1706 bool permissionToTake = true;
1707 bool permissionToTakeCopy = true;
1708 bool permissionToDelete = true;
1709 1703
1710 foreach (uint localID in localIDs) 1704 foreach (uint localID in localIDs)
1711 { 1705 {
1706 // Start with true for both, then remove the flags if objects
1707 // that we can't derez are part of the selection
1708 bool permissionToTake = true;
1709 bool permissionToTakeCopy = true;
1710 bool permissionToDelete = true;
1711
1712 // Invalid id 1712 // Invalid id
1713 SceneObjectPart part = GetSceneObjectPart(localID); 1713 SceneObjectPart part = GetSceneObjectPart(localID);
1714 if (part == null) 1714 if (part == null)
1715 {
1716 //Client still thinks the object exists, kill it
1717 deleteIDs.Add(localID);
1715 continue; 1718 continue;
1719 }
1716 1720
1717 // Already deleted by someone else 1721 // Already deleted by someone else
1718 if (part.ParentGroup == null || part.ParentGroup.IsDeleted) 1722 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
1723 {
1724 //Client still thinks the object exists, kill it
1725 deleteIDs.Add(localID);
1719 continue; 1726 continue;
1727 }
1720 1728
1721 // Can't delete child prims 1729 // Can't delete child prims
1722 if (part != part.ParentGroup.RootPart) 1730 if (part != part.ParentGroup.RootPart)
@@ -1724,9 +1732,6 @@ namespace OpenSim.Region.Framework.Scenes
1724 1732
1725 SceneObjectGroup grp = part.ParentGroup; 1733 SceneObjectGroup grp = part.ParentGroup;
1726 1734
1727 deleteIDs.Add(localID);
1728 deleteGroups.Add(grp);
1729
1730 if (remoteClient == null) 1735 if (remoteClient == null)
1731 { 1736 {
1732 // Autoreturn has a null client. Nothing else does. So 1737 // Autoreturn has a null client. Nothing else does. So
@@ -1743,80 +1748,104 @@ namespace OpenSim.Region.Framework.Scenes
1743 } 1748 }
1744 else 1749 else
1745 { 1750 {
1746 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) 1751 if (action == DeRezAction.TakeCopy)
1752 {
1753 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
1754 permissionToTakeCopy = false;
1755 }
1756 else
1757 {
1747 permissionToTakeCopy = false; 1758 permissionToTakeCopy = false;
1748 1759 }
1749 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) 1760 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
1750 permissionToTake = false; 1761 permissionToTake = false;
1751 1762
1752 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId)) 1763 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId))
1753 permissionToDelete = false; 1764 permissionToDelete = false;
1754 } 1765 }
1755 }
1756 1766
1757 // Handle god perms 1767 // Handle god perms
1758 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) 1768 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
1759 { 1769 {
1760 permissionToTake = true; 1770 permissionToTake = true;
1761 permissionToTakeCopy = true; 1771 permissionToTakeCopy = true;
1762 permissionToDelete = true; 1772 permissionToDelete = true;
1763 } 1773 }
1764 1774
1765 // If we're re-saving, we don't even want to delete 1775 // If we're re-saving, we don't even want to delete
1766 if (action == DeRezAction.SaveToExistingUserInventoryItem) 1776 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1767 permissionToDelete = false; 1777 permissionToDelete = false;
1768 1778
1769 // if we want to take a copy, we also don't want to delete 1779 // if we want to take a copy, we also don't want to delete
1770 // Note: after this point, the permissionToTakeCopy flag 1780 // Note: after this point, the permissionToTakeCopy flag
1771 // becomes irrelevant. It already includes the permissionToTake 1781 // becomes irrelevant. It already includes the permissionToTake
1772 // permission and after excluding no copy items here, we can 1782 // permission and after excluding no copy items here, we can
1773 // just use that. 1783 // just use that.
1774 if (action == DeRezAction.TakeCopy) 1784 if (action == DeRezAction.TakeCopy)
1775 { 1785 {
1776 // If we don't have permission, stop right here 1786 // If we don't have permission, stop right here
1777 if (!permissionToTakeCopy) 1787 if (!permissionToTakeCopy)
1778 return; 1788 return;
1779 1789
1780 permissionToTake = true; 1790 permissionToTake = true;
1781 // Don't delete 1791 // Don't delete
1782 permissionToDelete = false; 1792 permissionToDelete = false;
1783 } 1793 }
1784 1794
1785 if (action == DeRezAction.Return) 1795 if (action == DeRezAction.Return)
1786 {
1787 if (remoteClient != null)
1788 { 1796 {
1789 if (Permissions.CanReturnObjects( 1797 if (remoteClient != null)
1790 null,
1791 remoteClient.AgentId,
1792 deleteGroups))
1793 { 1798 {
1794 permissionToTake = true; 1799 if (Permissions.CanReturnObjects(
1795 permissionToDelete = true; 1800 null,
1796 1801 remoteClient.AgentId,
1797 foreach (SceneObjectGroup g in deleteGroups) 1802 deleteGroups))
1798 { 1803 {
1799 AddReturn(g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); 1804 permissionToTake = true;
1805 permissionToDelete = true;
1806
1807 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1800 } 1808 }
1801 } 1809 }
1810 else // Auto return passes through here with null agent
1811 {
1812 permissionToTake = true;
1813 permissionToDelete = true;
1814 }
1802 } 1815 }
1803 else // Auto return passes through here with null agent 1816
1817 if (permissionToTake && (!permissionToDelete))
1818 takeGroups.Add(grp);
1819
1820 if (permissionToDelete)
1804 { 1821 {
1805 permissionToTake = true; 1822 if (permissionToTake)
1806 permissionToDelete = true; 1823 deleteGroups.Add(grp);
1824 deleteIDs.Add(grp.LocalId);
1807 } 1825 }
1808 } 1826 }
1809 1827
1810 if (permissionToTake) 1828 SendKillObject(deleteIDs);
1829
1830 if (deleteGroups.Count > 0)
1811 { 1831 {
1832 foreach (SceneObjectGroup g in deleteGroups)
1833 deleteIDs.Remove(g.LocalId);
1834
1812 m_asyncSceneObjectDeleter.DeleteToInventory( 1835 m_asyncSceneObjectDeleter.DeleteToInventory(
1813 action, destinationID, deleteGroups, remoteClient, 1836 action, destinationID, deleteGroups, remoteClient,
1814 permissionToDelete); 1837 true);
1815 } 1838 }
1816 else if (permissionToDelete) 1839 if (takeGroups.Count > 0)
1840 {
1841 m_asyncSceneObjectDeleter.DeleteToInventory(
1842 action, destinationID, takeGroups, remoteClient,
1843 false);
1844 }
1845 if (deleteIDs.Count > 0)
1817 { 1846 {
1818 foreach (SceneObjectGroup g in deleteGroups) 1847 foreach (SceneObjectGroup g in deleteGroups)
1819 DeleteSceneObject(g, false); 1848 DeleteSceneObject(g, true);
1820 } 1849 }
1821 } 1850 }
1822 1851
@@ -1868,21 +1897,29 @@ namespace OpenSim.Region.Framework.Scenes
1868 else // oopsies 1897 else // oopsies
1869 item.Folder = UUID.Zero; 1898 item.Folder = UUID.Zero;
1870 1899
1900 // Set up base perms properly
1901 uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify);
1902 permsBase &= grp.RootPart.BaseMask;
1903 permsBase |= (uint)PermissionMask.Move;
1904
1905 // Make sure we don't lock it
1906 grp.RootPart.NextOwnerMask |= (uint)PermissionMask.Move;
1907
1871 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions()) 1908 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions())
1872 { 1909 {
1873 item.BasePermissions = grp.RootPart.NextOwnerMask; 1910 item.BasePermissions = permsBase & grp.RootPart.NextOwnerMask;
1874 item.CurrentPermissions = grp.RootPart.NextOwnerMask; 1911 item.CurrentPermissions = permsBase & grp.RootPart.NextOwnerMask;
1875 item.NextPermissions = grp.RootPart.NextOwnerMask; 1912 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
1876 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; 1913 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
1877 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; 1914 item.GroupPermissions = permsBase & grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
1878 } 1915 }
1879 else 1916 else
1880 { 1917 {
1881 item.BasePermissions = grp.RootPart.BaseMask; 1918 item.BasePermissions = permsBase;
1882 item.CurrentPermissions = grp.RootPart.OwnerMask; 1919 item.CurrentPermissions = permsBase & grp.RootPart.OwnerMask;
1883 item.NextPermissions = grp.RootPart.NextOwnerMask; 1920 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
1884 item.EveryOnePermissions = grp.RootPart.EveryoneMask; 1921 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask;
1885 item.GroupPermissions = grp.RootPart.GroupMask; 1922 item.GroupPermissions = permsBase & grp.RootPart.GroupMask;
1886 } 1923 }
1887 item.CreationDate = Util.UnixTimeSinceEpoch(); 1924 item.CreationDate = Util.UnixTimeSinceEpoch();
1888 1925
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index e27b2ba..066e504 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -84,6 +84,7 @@ namespace OpenSim.Region.Framework.Scenes
84 // TODO: need to figure out how allow client agents but deny 84 // TODO: need to figure out how allow client agents but deny
85 // root agents when ACL denies access to root agent 85 // root agents when ACL denies access to root agent
86 public bool m_strictAccessControl = true; 86 public bool m_strictAccessControl = true;
87 public bool m_seeIntoBannedRegion = false;
87 public int MaxUndoCount = 5; 88 public int MaxUndoCount = 5;
88 public bool LoginsDisabled = true; 89 public bool LoginsDisabled = true;
89 public bool LoadingPrims; 90 public bool LoadingPrims;
@@ -102,6 +103,7 @@ namespace OpenSim.Region.Framework.Scenes
102 protected ModuleLoader m_moduleLoader; 103 protected ModuleLoader m_moduleLoader;
103 protected AgentCircuitManager m_authenticateHandler; 104 protected AgentCircuitManager m_authenticateHandler;
104 protected SceneCommunicationService m_sceneGridService; 105 protected SceneCommunicationService m_sceneGridService;
106 protected ISnmpModule m_snmpService = null;
105 107
106 protected ISimulationDataService m_SimulationDataService; 108 protected ISimulationDataService m_SimulationDataService;
107 protected IEstateDataService m_EstateDataService; 109 protected IEstateDataService m_EstateDataService;
@@ -163,6 +165,7 @@ namespace OpenSim.Region.Framework.Scenes
163 private int landMS; 165 private int landMS;
164 private int lastCompletedFrame; 166 private int lastCompletedFrame;
165 167
168 public bool CombineRegions = false;
166 private bool m_physics_enabled = true; 169 private bool m_physics_enabled = true;
167 private bool m_scripts_enabled = true; 170 private bool m_scripts_enabled = true;
168 private string m_defaultScriptEngine; 171 private string m_defaultScriptEngine;
@@ -171,6 +174,8 @@ namespace OpenSim.Region.Framework.Scenes
171 private volatile bool shuttingdown; 174 private volatile bool shuttingdown;
172 175
173 private int m_lastUpdate; 176 private int m_lastUpdate;
177 private int m_lastIncoming;
178 private int m_lastOutgoing;
174 private bool m_firstHeartbeat = true; 179 private bool m_firstHeartbeat = true;
175 180
176 private object m_deleting_scene_object = new object(); 181 private object m_deleting_scene_object = new object();
@@ -222,6 +227,19 @@ namespace OpenSim.Region.Framework.Scenes
222 get { return m_sceneGridService; } 227 get { return m_sceneGridService; }
223 } 228 }
224 229
230 public ISnmpModule SnmpService
231 {
232 get
233 {
234 if (m_snmpService == null)
235 {
236 m_snmpService = RequestModuleInterface<ISnmpModule>();
237 }
238
239 return m_snmpService;
240 }
241 }
242
225 public ISimulationDataService SimulationDataService 243 public ISimulationDataService SimulationDataService
226 { 244 {
227 get 245 get
@@ -553,6 +571,8 @@ namespace OpenSim.Region.Framework.Scenes
553 m_regionName = m_regInfo.RegionName; 571 m_regionName = m_regInfo.RegionName;
554 m_datastore = m_regInfo.DataStore; 572 m_datastore = m_regInfo.DataStore;
555 m_lastUpdate = Util.EnvironmentTickCount(); 573 m_lastUpdate = Util.EnvironmentTickCount();
574 m_lastIncoming = 0;
575 m_lastOutgoing = 0;
556 576
557 m_physicalPrim = physicalPrim; 577 m_physicalPrim = physicalPrim;
558 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor; 578 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor;
@@ -566,6 +586,8 @@ namespace OpenSim.Region.Framework.Scenes
566 #region Region Settings 586 #region Region Settings
567 587
568 // Load region settings 588 // Load region settings
589 m_regInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(m_regInfo.RegionID);
590
569 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID); 591 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID);
570 if (estateDataService != null) 592 if (estateDataService != null)
571 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); 593 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false);
@@ -625,9 +647,10 @@ namespace OpenSim.Region.Framework.Scenes
625 //Animation states 647 //Animation states
626 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); 648 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
627 // TODO: Change default to true once the feature is supported 649 // TODO: Change default to true once the feature is supported
628 m_usePreJump = startupConfig.GetBoolean("enableprejump", false); 650 m_usePreJump = startupConfig.GetBoolean("enableprejump", true);
629
630 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); 651 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
652
653 m_log.DebugFormat("[SCENE]: prejump is {0}", m_usePreJump ? "ON" : "OFF");
631 if (RegionInfo.NonphysPrimMax > 0) 654 if (RegionInfo.NonphysPrimMax > 0)
632 { 655 {
633 m_maxNonphys = RegionInfo.NonphysPrimMax; 656 m_maxNonphys = RegionInfo.NonphysPrimMax;
@@ -659,6 +682,7 @@ namespace OpenSim.Region.Framework.Scenes
659 m_persistAfter *= 10000000; 682 m_persistAfter *= 10000000;
660 683
661 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 684 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
685 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
662 686
663 IConfig packetConfig = m_config.Configs["PacketPool"]; 687 IConfig packetConfig = m_config.Configs["PacketPool"];
664 if (packetConfig != null) 688 if (packetConfig != null)
@@ -668,6 +692,8 @@ namespace OpenSim.Region.Framework.Scenes
668 } 692 }
669 693
670 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 694 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
695 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
696 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
671 697
672 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 698 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
673 if (m_generateMaptiles) 699 if (m_generateMaptiles)
@@ -692,9 +718,9 @@ namespace OpenSim.Region.Framework.Scenes
692 } 718 }
693 } 719 }
694 } 720 }
695 catch 721 catch (Exception e)
696 { 722 {
697 m_log.Warn("[SCENE]: Failed to load StartupConfig"); 723 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
698 } 724 }
699 725
700 #endregion Region Config 726 #endregion Region Config
@@ -1065,7 +1091,9 @@ namespace OpenSim.Region.Framework.Scenes
1065 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); 1091 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1066 if (HeartbeatThread != null) 1092 if (HeartbeatThread != null)
1067 { 1093 {
1094 m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName);
1068 HeartbeatThread.Abort(); 1095 HeartbeatThread.Abort();
1096 Watchdog.RemoveThread(HeartbeatThread.ManagedThreadId);
1069 HeartbeatThread = null; 1097 HeartbeatThread = null;
1070 } 1098 }
1071 m_lastUpdate = Util.EnvironmentTickCount(); 1099 m_lastUpdate = Util.EnvironmentTickCount();
@@ -1188,9 +1216,6 @@ namespace OpenSim.Region.Framework.Scenes
1188 try 1216 try
1189 { 1217 {
1190 Update(); 1218 Update();
1191
1192 m_lastUpdate = Util.EnvironmentTickCount();
1193 m_firstHeartbeat = false;
1194 } 1219 }
1195 catch (ThreadAbortException) 1220 catch (ThreadAbortException)
1196 { 1221 {
@@ -1381,6 +1406,9 @@ namespace OpenSim.Region.Framework.Scenes
1381 1406
1382 // Tell the watchdog that this thread is still alive 1407 // Tell the watchdog that this thread is still alive
1383 Watchdog.UpdateThread(); 1408 Watchdog.UpdateThread();
1409
1410 m_lastUpdate = Util.EnvironmentTickCount();
1411 m_firstHeartbeat = false;
1384 } 1412 }
1385 } 1413 }
1386 1414
@@ -1400,9 +1428,9 @@ namespace OpenSim.Region.Framework.Scenes
1400 1428
1401 private void CheckAtTargets() 1429 private void CheckAtTargets()
1402 { 1430 {
1403 Dictionary<UUID, SceneObjectGroup>.ValueCollection objs; 1431 List<SceneObjectGroup> objs = new List<SceneObjectGroup>();
1404 lock (m_groupsWithTargets) 1432 lock (m_groupsWithTargets)
1405 objs = m_groupsWithTargets.Values; 1433 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1406 1434
1407 foreach (SceneObjectGroup entry in objs) 1435 foreach (SceneObjectGroup entry in objs)
1408 entry.checkAtTargets(); 1436 entry.checkAtTargets();
@@ -1736,14 +1764,24 @@ namespace OpenSim.Region.Framework.Scenes
1736 /// <returns></returns> 1764 /// <returns></returns>
1737 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) 1765 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1738 { 1766 {
1767
1768 float wheight = (float)RegionInfo.RegionSettings.WaterHeight;
1769 Vector3 wpos = Vector3.Zero;
1770 // Check for water surface intersection from above
1771 if ( (RayStart.Z > wheight) && (RayEnd.Z < wheight) )
1772 {
1773 float ratio = (RayStart.Z - wheight) / (RayStart.Z - RayEnd.Z);
1774 wpos.X = RayStart.X - (ratio * (RayStart.X - RayEnd.X));
1775 wpos.Y = RayStart.Y - (ratio * (RayStart.Y - RayEnd.Y));
1776 wpos.Z = wheight;
1777 }
1778
1739 Vector3 pos = Vector3.Zero; 1779 Vector3 pos = Vector3.Zero;
1740 if (RayEndIsIntersection == (byte)1) 1780 if (RayEndIsIntersection == (byte)1)
1741 { 1781 {
1742 pos = RayEnd; 1782 pos = RayEnd;
1743 return pos;
1744 } 1783 }
1745 1784 else if (RayTargetID != UUID.Zero)
1746 if (RayTargetID != UUID.Zero)
1747 { 1785 {
1748 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 1786 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1749 1787
@@ -1765,7 +1803,7 @@ namespace OpenSim.Region.Framework.Scenes
1765 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 1803 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1766 1804
1767 // Un-comment out the following line to Get Raytrace results printed to the console. 1805 // Un-comment out the following line to Get Raytrace results printed to the console.
1768 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 1806 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1769 float ScaleOffset = 0.5f; 1807 float ScaleOffset = 0.5f;
1770 1808
1771 // If we hit something 1809 // If we hit something
@@ -1788,13 +1826,10 @@ namespace OpenSim.Region.Framework.Scenes
1788 //pos.Z -= 0.25F; 1826 //pos.Z -= 0.25F;
1789 1827
1790 } 1828 }
1791
1792 return pos;
1793 } 1829 }
1794 else 1830 else
1795 { 1831 {
1796 // We don't have a target here, so we're going to raytrace all the objects in the scene. 1832 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1797
1798 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); 1833 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1799 1834
1800 // Un-comment the following line to print the raytrace results to the console. 1835 // Un-comment the following line to print the raytrace results to the console.
@@ -1803,13 +1838,12 @@ namespace OpenSim.Region.Framework.Scenes
1803 if (ei.HitTF) 1838 if (ei.HitTF)
1804 { 1839 {
1805 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 1840 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1806 } else 1841 }
1842 else
1807 { 1843 {
1808 // fall back to our stupid functionality 1844 // fall back to our stupid functionality
1809 pos = RayEnd; 1845 pos = RayEnd;
1810 } 1846 }
1811
1812 return pos;
1813 } 1847 }
1814 } 1848 }
1815 else 1849 else
@@ -1820,8 +1854,12 @@ namespace OpenSim.Region.Framework.Scenes
1820 //increase height so its above the ground. 1854 //increase height so its above the ground.
1821 //should be getting the normal of the ground at the rez point and using that? 1855 //should be getting the normal of the ground at the rez point and using that?
1822 pos.Z += scale.Z / 2f; 1856 pos.Z += scale.Z / 2f;
1823 return pos; 1857// return pos;
1824 } 1858 }
1859
1860 // check against posible water intercept
1861 if (wpos.Z > pos.Z) pos = wpos;
1862 return pos;
1825 } 1863 }
1826 1864
1827 1865
@@ -1901,7 +1939,10 @@ namespace OpenSim.Region.Framework.Scenes
1901 public bool AddRestoredSceneObject( 1939 public bool AddRestoredSceneObject(
1902 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 1940 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
1903 { 1941 {
1904 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 1942 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
1943 if (result)
1944 sceneObject.IsDeleted = false;
1945 return result;
1905 } 1946 }
1906 1947
1907 /// <summary> 1948 /// <summary>
@@ -1978,6 +2019,15 @@ namespace OpenSim.Region.Framework.Scenes
1978 /// </summary> 2019 /// </summary>
1979 public void DeleteAllSceneObjects() 2020 public void DeleteAllSceneObjects()
1980 { 2021 {
2022 DeleteAllSceneObjects(false);
2023 }
2024
2025 /// <summary>
2026 /// Delete every object from the scene. This does not include attachments worn by avatars.
2027 /// </summary>
2028 public void DeleteAllSceneObjects(bool exceptNoCopy)
2029 {
2030 List<SceneObjectGroup> toReturn = new List<SceneObjectGroup>();
1981 lock (Entities) 2031 lock (Entities)
1982 { 2032 {
1983 EntityBase[] entities = Entities.GetEntities(); 2033 EntityBase[] entities = Entities.GetEntities();
@@ -1986,11 +2036,24 @@ namespace OpenSim.Region.Framework.Scenes
1986 if (e is SceneObjectGroup) 2036 if (e is SceneObjectGroup)
1987 { 2037 {
1988 SceneObjectGroup sog = (SceneObjectGroup)e; 2038 SceneObjectGroup sog = (SceneObjectGroup)e;
1989 if (!sog.IsAttachment) 2039 if (sog != null && !sog.IsAttachment)
1990 DeleteSceneObject((SceneObjectGroup)e, false); 2040 {
2041 if (!exceptNoCopy || ((sog.GetEffectivePermissions() & (uint)PermissionMask.Copy) != 0))
2042 {
2043 DeleteSceneObject((SceneObjectGroup)e, false);
2044 }
2045 else
2046 {
2047 toReturn.Add((SceneObjectGroup)e);
2048 }
2049 }
1991 } 2050 }
1992 } 2051 }
1993 } 2052 }
2053 if (toReturn.Count > 0)
2054 {
2055 returnObjects(toReturn.ToArray(), UUID.Zero);
2056 }
1994 } 2057 }
1995 2058
1996 /// <summary> 2059 /// <summary>
@@ -2039,6 +2102,8 @@ namespace OpenSim.Region.Framework.Scenes
2039 } 2102 }
2040 2103
2041 group.DeleteGroupFromScene(silent); 2104 group.DeleteGroupFromScene(silent);
2105 if (!silent)
2106 SendKillObject(new List<uint>() { group.LocalId });
2042 2107
2043// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2108// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2044 } 2109 }
@@ -2369,6 +2434,12 @@ namespace OpenSim.Region.Framework.Scenes
2369 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns> 2434 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2370 public bool AddSceneObject(SceneObjectGroup sceneObject) 2435 public bool AddSceneObject(SceneObjectGroup sceneObject)
2371 { 2436 {
2437 if (sceneObject.OwnerID == UUID.Zero)
2438 {
2439 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID);
2440 return false;
2441 }
2442
2372 // If the user is banned, we won't let any of their objects 2443 // If the user is banned, we won't let any of their objects
2373 // enter. Period. 2444 // enter. Period.
2374 // 2445 //
@@ -2416,15 +2487,28 @@ namespace OpenSim.Region.Framework.Scenes
2416 2487
2417 if (AttachmentsModule != null) 2488 if (AttachmentsModule != null)
2418 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false); 2489 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false);
2490
2491 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was found, attaching", sceneObject.UUID);
2419 } 2492 }
2420 else 2493 else
2421 { 2494 {
2495 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID);
2422 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2496 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2423 RootPrim.AddFlag(PrimFlags.TemporaryOnRez); 2497 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2424 } 2498 }
2499 if (sceneObject.OwnerID == UUID.Zero)
2500 {
2501 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID);
2502 return false;
2503 }
2425 } 2504 }
2426 else 2505 else
2427 { 2506 {
2507 if (sceneObject.OwnerID == UUID.Zero)
2508 {
2509 m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID);
2510 return false;
2511 }
2428 AddRestoredSceneObject(sceneObject, true, false); 2512 AddRestoredSceneObject(sceneObject, true, false);
2429 2513
2430 if (!Permissions.CanObjectEntry(sceneObject.UUID, 2514 if (!Permissions.CanObjectEntry(sceneObject.UUID,
@@ -2536,12 +2620,19 @@ namespace OpenSim.Region.Framework.Scenes
2536 } 2620 }
2537 } 2621 }
2538 2622
2539 if (GetScenePresence(client.AgentId) != null) 2623 if (TryGetScenePresence(client.AgentId, out presence))
2540 { 2624 {
2541 m_LastLogin = Util.EnvironmentTickCount(); 2625 m_LastLogin = Util.EnvironmentTickCount();
2542 EventManager.TriggerOnNewClient(client); 2626 EventManager.TriggerOnNewClient(client);
2543 if (vialogin) 2627 if (vialogin)
2628 {
2544 EventManager.TriggerOnClientLogin(client); 2629 EventManager.TriggerOnClientLogin(client);
2630
2631 // Send initial parcel data
2632 Vector3 pos = presence.AbsolutePosition;
2633 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2634 land.SendLandUpdateToClient(presence.ControllingClient);
2635 }
2545 } 2636 }
2546 } 2637 }
2547 2638
@@ -2697,6 +2788,7 @@ namespace OpenSim.Region.Framework.Scenes
2697 client.OnFetchInventory += HandleFetchInventory; 2788 client.OnFetchInventory += HandleFetchInventory;
2698 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 2789 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2699 client.OnCopyInventoryItem += CopyInventoryItem; 2790 client.OnCopyInventoryItem += CopyInventoryItem;
2791 client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy;
2700 client.OnMoveInventoryItem += MoveInventoryItem; 2792 client.OnMoveInventoryItem += MoveInventoryItem;
2701 client.OnRemoveInventoryItem += RemoveInventoryItem; 2793 client.OnRemoveInventoryItem += RemoveInventoryItem;
2702 client.OnRemoveInventoryFolder += RemoveInventoryFolder; 2794 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
@@ -2875,15 +2967,16 @@ namespace OpenSim.Region.Framework.Scenes
2875 /// </summary> 2967 /// </summary>
2876 /// <param name="agentId">The avatar's Unique ID</param> 2968 /// <param name="agentId">The avatar's Unique ID</param>
2877 /// <param name="client">The IClientAPI for the client</param> 2969 /// <param name="client">The IClientAPI for the client</param>
2878 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 2970 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
2879 { 2971 {
2880 if (m_teleportModule != null) 2972 if (m_teleportModule != null)
2881 m_teleportModule.TeleportHome(agentId, client); 2973 return m_teleportModule.TeleportHome(agentId, client);
2882 else 2974 else
2883 { 2975 {
2884 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 2976 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
2885 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 2977 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
2886 } 2978 }
2979 return false;
2887 } 2980 }
2888 2981
2889 /// <summary> 2982 /// <summary>
@@ -2982,6 +3075,16 @@ namespace OpenSim.Region.Framework.Scenes
2982 /// <param name="flags"></param> 3075 /// <param name="flags"></param>
2983 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3076 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2984 { 3077 {
3078 //Add half the avatar's height so that the user doesn't fall through prims
3079 ScenePresence presence;
3080 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3081 {
3082 if (presence.Appearance != null)
3083 {
3084 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3085 }
3086 }
3087
2985 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3088 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
2986 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3089 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2987 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3090 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
@@ -3075,7 +3178,9 @@ namespace OpenSim.Region.Framework.Scenes
3075 regions.Remove(RegionInfo.RegionHandle); 3178 regions.Remove(RegionInfo.RegionHandle);
3076 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3179 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3077 } 3180 }
3181 m_log.Debug("[Scene] Beginning ClientClosed");
3078 m_eventManager.TriggerClientClosed(agentID, this); 3182 m_eventManager.TriggerClientClosed(agentID, this);
3183 m_log.Debug("[Scene] Finished ClientClosed");
3079 } 3184 }
3080 catch (NullReferenceException) 3185 catch (NullReferenceException)
3081 { 3186 {
@@ -3083,7 +3188,12 @@ namespace OpenSim.Region.Framework.Scenes
3083 // Avatar is already disposed :/ 3188 // Avatar is already disposed :/
3084 } 3189 }
3085 3190
3191 m_log.Debug("[Scene] Beginning OnRemovePresence");
3086 m_eventManager.TriggerOnRemovePresence(agentID); 3192 m_eventManager.TriggerOnRemovePresence(agentID);
3193 m_log.Debug("[Scene] Finished OnRemovePresence");
3194
3195 if (avatar != null && (!avatar.IsChildAgent))
3196 avatar.SaveChangedAttachments();
3087 3197
3088 if (avatar != null && (!avatar.IsChildAgent)) 3198 if (avatar != null && (!avatar.IsChildAgent))
3089 avatar.SaveChangedAttachments(); 3199 avatar.SaveChangedAttachments();
@@ -3092,7 +3202,7 @@ namespace OpenSim.Region.Framework.Scenes
3092 delegate(IClientAPI client) 3202 delegate(IClientAPI client)
3093 { 3203 {
3094 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3204 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3095 try { client.SendKillObject(avatar.RegionHandle, avatar.LocalId); } 3205 try { client.SendKillObject(avatar.RegionHandle, new List<uint>() { avatar.LocalId}); }
3096 catch (NullReferenceException) { } 3206 catch (NullReferenceException) { }
3097 }); 3207 });
3098 3208
@@ -3103,8 +3213,11 @@ namespace OpenSim.Region.Framework.Scenes
3103 } 3213 }
3104 3214
3105 // Remove the avatar from the scene 3215 // Remove the avatar from the scene
3216 m_log.Debug("[Scene] Begin RemoveScenePresence");
3106 m_sceneGraph.RemoveScenePresence(agentID); 3217 m_sceneGraph.RemoveScenePresence(agentID);
3218 m_log.Debug("[Scene] Finished RemoveScenePresence. Removing the client manager");
3107 m_clientManager.Remove(agentID); 3219 m_clientManager.Remove(agentID);
3220 m_log.Debug("[Scene] Removed the client manager. Firing avatar.close");
3108 3221
3109 try 3222 try
3110 { 3223 {
@@ -3118,9 +3231,10 @@ namespace OpenSim.Region.Framework.Scenes
3118 { 3231 {
3119 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString()); 3232 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString());
3120 } 3233 }
3121 3234 m_log.Debug("[Scene] Done. Firing RemoveCircuit");
3122 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3235 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3123 CleanDroppedAttachments(); 3236 CleanDroppedAttachments();
3237 m_log.Debug("[Scene] The avatar has left the building");
3124 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3238 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3125 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); 3239 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3126 } 3240 }
@@ -3151,18 +3265,24 @@ namespace OpenSim.Region.Framework.Scenes
3151 3265
3152 #region Entities 3266 #region Entities
3153 3267
3154 public void SendKillObject(uint localID) 3268 public void SendKillObject(List<uint> localIDs)
3155 { 3269 {
3156 SceneObjectPart part = GetSceneObjectPart(localID); 3270 List<uint> deleteIDs = new List<uint>();
3157 if (part != null) // It is a prim 3271
3272 foreach (uint localID in localIDs)
3158 { 3273 {
3159 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid 3274 SceneObjectPart part = GetSceneObjectPart(localID);
3275 if (part != null) // It is a prim
3160 { 3276 {
3161 if (part.ParentGroup.RootPart != part) // Child part 3277 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
3162 return; 3278 {
3279 if (part.ParentGroup.RootPart != part) // Child part
3280 continue;
3281 }
3163 } 3282 }
3283 deleteIDs.Add(localID);
3164 } 3284 }
3165 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); 3285 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); });
3166 } 3286 }
3167 3287
3168 #endregion 3288 #endregion
@@ -3180,7 +3300,6 @@ namespace OpenSim.Region.Framework.Scenes
3180 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate; 3300 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
3181 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar; 3301 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar;
3182 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid; 3302 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid;
3183 m_sceneGridService.KiPrimitive += SendKillObject;
3184 m_sceneGridService.OnGetLandData += GetLandData; 3303 m_sceneGridService.OnGetLandData += GetLandData;
3185 } 3304 }
3186 3305
@@ -3189,7 +3308,6 @@ namespace OpenSim.Region.Framework.Scenes
3189 /// </summary> 3308 /// </summary>
3190 public void UnRegisterRegionWithComms() 3309 public void UnRegisterRegionWithComms()
3191 { 3310 {
3192 m_sceneGridService.KiPrimitive -= SendKillObject;
3193 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid; 3311 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid;
3194 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar; 3312 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar;
3195 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate; 3313 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
@@ -3276,6 +3394,7 @@ namespace OpenSim.Region.Framework.Scenes
3276 { 3394 {
3277 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3395 if (land != null && !TestLandRestrictions(agent, land, out reason))
3278 { 3396 {
3397 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3279 return false; 3398 return false;
3280 } 3399 }
3281 } 3400 }
@@ -3393,6 +3512,8 @@ namespace OpenSim.Region.Framework.Scenes
3393 } 3512 }
3394 } 3513 }
3395 // Honor parcel landing type and position. 3514 // Honor parcel landing type and position.
3515 /*
3516 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3396 if (land != null) 3517 if (land != null)
3397 { 3518 {
3398 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3519 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
@@ -3400,6 +3521,7 @@ namespace OpenSim.Region.Framework.Scenes
3400 agent.startpos = land.LandData.UserLocation; 3521 agent.startpos = land.LandData.UserLocation;
3401 } 3522 }
3402 } 3523 }
3524 */// This is now handled properly in ScenePresence.MakeRootAgent
3403 } 3525 }
3404 3526
3405 return true; 3527 return true;
@@ -3495,7 +3617,7 @@ namespace OpenSim.Region.Framework.Scenes
3495 3617
3496 if (m_regInfo.EstateSettings != null) 3618 if (m_regInfo.EstateSettings != null)
3497 { 3619 {
3498 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID)) 3620 if ((!m_seeIntoBannedRegion) && m_regInfo.EstateSettings.IsBanned(agent.AgentID))
3499 { 3621 {
3500 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", 3622 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
3501 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3623 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
@@ -3685,6 +3807,12 @@ namespace OpenSim.Region.Framework.Scenes
3685 3807
3686 // We have to wait until the viewer contacts this region after receiving EAC. 3808 // We have to wait until the viewer contacts this region after receiving EAC.
3687 // That calls AddNewClient, which finally creates the ScenePresence 3809 // That calls AddNewClient, which finally creates the ScenePresence
3810 if (m_regInfo.EstateSettings.IsBanned(cAgentData.AgentID))
3811 {
3812 m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: banned", cAgentData.AgentID);
3813 return false;
3814 }
3815
3688 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); 3816 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
3689 if (nearestParcel == null) 3817 if (nearestParcel == null)
3690 { 3818 {
@@ -3692,6 +3820,14 @@ namespace OpenSim.Region.Framework.Scenes
3692 return false; 3820 return false;
3693 } 3821 }
3694 3822
3823 int num = m_sceneGraph.GetNumberOfScenePresences();
3824
3825 if (num >= RegionInfo.RegionSettings.AgentLimit)
3826 {
3827 if (!Permissions.IsAdministrator(cAgentData.AgentID))
3828 return false;
3829 }
3830
3695 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); 3831 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
3696 3832
3697 if (childAgentUpdate != null) 3833 if (childAgentUpdate != null)
@@ -3758,12 +3894,22 @@ namespace OpenSim.Region.Framework.Scenes
3758 return false; 3894 return false;
3759 } 3895 }
3760 3896
3897 public bool IncomingCloseAgent(UUID agentID)
3898 {
3899 return IncomingCloseAgent(agentID, false);
3900 }
3901
3902 public bool IncomingCloseChildAgent(UUID agentID)
3903 {
3904 return IncomingCloseAgent(agentID, true);
3905 }
3906
3761 /// <summary> 3907 /// <summary>
3762 /// Tell a single agent to disconnect from the region. 3908 /// Tell a single agent to disconnect from the region.
3763 /// </summary> 3909 /// </summary>
3764 /// <param name="regionHandle"></param>
3765 /// <param name="agentID"></param> 3910 /// <param name="agentID"></param>
3766 public bool IncomingCloseAgent(UUID agentID) 3911 /// <param name="childOnly"></param>
3912 public bool IncomingCloseAgent(UUID agentID, bool childOnly)
3767 { 3913 {
3768 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 3914 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
3769 3915
@@ -3775,7 +3921,7 @@ namespace OpenSim.Region.Framework.Scenes
3775 { 3921 {
3776 m_sceneGraph.removeUserCount(false); 3922 m_sceneGraph.removeUserCount(false);
3777 } 3923 }
3778 else 3924 else if (!childOnly)
3779 { 3925 {
3780 m_sceneGraph.removeUserCount(true); 3926 m_sceneGraph.removeUserCount(true);
3781 } 3927 }
@@ -3791,9 +3937,12 @@ namespace OpenSim.Region.Framework.Scenes
3791 } 3937 }
3792 else 3938 else
3793 presence.ControllingClient.SendShutdownConnectionNotice(); 3939 presence.ControllingClient.SendShutdownConnectionNotice();
3940 presence.ControllingClient.Close(false);
3941 }
3942 else if (!childOnly)
3943 {
3944 presence.ControllingClient.Close(true);
3794 } 3945 }
3795
3796 presence.ControllingClient.Close();
3797 return true; 3946 return true;
3798 } 3947 }
3799 3948
@@ -4401,34 +4550,66 @@ namespace OpenSim.Region.Framework.Scenes
4401 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID); 4550 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID);
4402 } 4551 }
4403 4552
4404 public int GetHealth() 4553 public int GetHealth(out int flags, out string message)
4405 { 4554 {
4406 // Returns: 4555 // Returns:
4407 // 1 = sim is up and accepting http requests. The heartbeat has 4556 // 1 = sim is up and accepting http requests. The heartbeat has
4408 // stopped and the sim is probably locked up, but a remote 4557 // stopped and the sim is probably locked up, but a remote
4409 // admin restart may succeed 4558 // admin restart may succeed
4410 // 4559 //
4411 // 2 = Sim is up and the heartbeat is running. The sim is likely 4560 // 2 = Sim is up and the heartbeat is running. The sim is likely
4412 // usable for people within and logins _may_ work 4561 // usable for people within
4562 //
4563 // 3 = Sim is up and one packet thread is running. Sim is
4564 // unstable and will not accept new logins
4413 // 4565 //
4414 // 3 = We have seen a new user enter within the past 4 minutes 4566 // 4 = Sim is up and both packet threads are running. Sim is
4567 // likely usable
4568 //
4569 // 5 = We have seen a new user enter within the past 4 minutes
4415 // which can be seen as positive confirmation of sim health 4570 // which can be seen as positive confirmation of sim health
4416 // 4571 //
4572
4573 flags = 0;
4574 message = String.Empty;
4575
4576 CheckHeartbeat();
4577
4578 if (m_firstHeartbeat || (m_lastIncoming == 0 && m_lastOutgoing == 0))
4579 {
4580 // We're still starting
4581 // 0 means "in startup", it can't happen another way, since
4582 // to get here, we must be able to accept http connections
4583 return 0;
4584 }
4585
4417 int health=1; // Start at 1, means we're up 4586 int health=1; // Start at 1, means we're up
4418 4587
4419 if ((Util.EnvironmentTickCountSubtract(m_lastUpdate)) < 1000) 4588 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) < 1000)
4589 {
4420 health+=1; 4590 health+=1;
4421 else 4591 flags |= 1;
4592 }
4593
4594 if (Util.EnvironmentTickCountSubtract(m_lastIncoming) < 1000)
4595 {
4596 health+=1;
4597 flags |= 2;
4598 }
4599
4600 if (Util.EnvironmentTickCountSubtract(m_lastOutgoing) < 1000)
4601 {
4602 health+=1;
4603 flags |= 4;
4604 }
4605
4606 if (flags != 7)
4422 return health; 4607 return health;
4423 4608
4424 // A login in the last 4 mins? We can't be doing too badly 4609 // A login in the last 4 mins? We can't be doing too badly
4425 // 4610 //
4426 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) 4611 if (Util.EnvironmentTickCountSubtract(m_LastLogin) < 240000)
4427 health++; 4612 health++;
4428 else
4429 return health;
4430
4431 CheckHeartbeat();
4432 4613
4433 return health; 4614 return health;
4434 } 4615 }
@@ -4621,7 +4802,7 @@ namespace OpenSim.Region.Framework.Scenes
4621 if (m_firstHeartbeat) 4802 if (m_firstHeartbeat)
4622 return; 4803 return;
4623 4804
4624 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 2000) 4805 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 10000)
4625 StartTimer(); 4806 StartTimer();
4626 } 4807 }
4627 4808
@@ -4879,8 +5060,17 @@ namespace OpenSim.Region.Framework.Scenes
4879 { 5060 {
4880 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ; 5061 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ;
4881 5062
5063 Vector3 vec = g.AbsolutePosition;
5064
4882 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); 5065 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
4883 5066
5067 ominX += vec.X;
5068 omaxX += vec.X;
5069 ominY += vec.Y;
5070 omaxY += vec.Y;
5071 ominZ += vec.Z;
5072 omaxZ += vec.Z;
5073
4884 if (minX > ominX) 5074 if (minX > ominX)
4885 minX = ominX; 5075 minX = ominX;
4886 if (minY > ominY) 5076 if (minY > ominY)
@@ -4950,10 +5140,28 @@ namespace OpenSim.Region.Framework.Scenes
4950 }); 5140 });
4951 } 5141 }
4952 5142
4953 foreach (SceneObjectGroup grp in objectsToDelete) 5143 if (objectsToDelete.Count > 0)
5144 {
5145 m_log.DebugFormat("[SCENE]: Starting delete of {0} dropped attachments", objectsToDelete.Count);
5146 foreach (SceneObjectGroup grp in objectsToDelete)
5147 {
5148 m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID);
5149 DeleteSceneObject(grp, true);
5150 }
5151 m_log.Debug("[SCENE]: Finished dropped attachment deletion");
5152 }
5153 }
5154
5155 public void ThreadAlive(int threadCode)
5156 {
5157 switch(threadCode)
4954 { 5158 {
4955 m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID); 5159 case 1: // Incoming
4956 DeleteSceneObject(grp, true); 5160 m_lastIncoming = Util.EnvironmentTickCount();
5161 break;
5162 case 2: // Incoming
5163 m_lastOutgoing = Util.EnvironmentTickCount();
5164 break;
4957 } 5165 }
4958 } 5166 }
4959 5167
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 69ebe9e..c8af4c3 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -44,8 +44,6 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
45namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
46{ 46{
47 public delegate void KiPrimitiveDelegate(uint localID);
48
49 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst); 47 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst);
50 48
51 /// <summary> 49 /// <summary>
@@ -113,8 +111,6 @@ namespace OpenSim.Region.Framework.Scenes
113// private LogOffUser handlerLogOffUser = null; 111// private LogOffUser handlerLogOffUser = null;
114// private GetLandData handlerGetLandData = null; // OnGetLandData 112// private GetLandData handlerGetLandData = null; // OnGetLandData
115 113
116 public KiPrimitiveDelegate KiPrimitive;
117
118 public SceneCommunicationService() 114 public SceneCommunicationService()
119 { 115 {
120 } 116 }
@@ -168,7 +164,7 @@ namespace OpenSim.Region.Framework.Scenes
168 164
169 if (neighbour != null) 165 if (neighbour != null)
170 { 166 {
171 m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize); 167 // m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize);
172 m_scene.EventManager.TriggerOnRegionUp(neighbour); 168 m_scene.EventManager.TriggerOnRegionUp(neighbour);
173 } 169 }
174 else 170 else
@@ -183,7 +179,7 @@ namespace OpenSim.Region.Framework.Scenes
183 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); 179 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
184 180
185 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); 181 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID);
186 m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count); 182 //m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count);
187 foreach (GridRegion n in neighbours) 183 foreach (GridRegion n in neighbours)
188 { 184 {
189 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; 185 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
@@ -267,14 +263,14 @@ namespace OpenSim.Region.Framework.Scenes
267 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle) 263 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
268 { 264 {
269 265
270 m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle); 266 //m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
271 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 267 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
272 268
273 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 269 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
274 uint x = 0, y = 0; 270 uint x = 0, y = 0;
275 Utils.LongToUInts(regionHandle, out x, out y); 271 Utils.LongToUInts(regionHandle, out x, out y);
276 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 272 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
277 m_scene.SimulationService.CloseAgent(destination, agentID); 273 m_scene.SimulationService.CloseChildAgent(destination, agentID);
278 } 274 }
279 275
280 private void SendCloseChildAgentCompleted(IAsyncResult iar) 276 private void SendCloseChildAgentCompleted(IAsyncResult iar)
@@ -293,7 +289,7 @@ namespace OpenSim.Region.Framework.Scenes
293 d); 289 d);
294 } 290 }
295 } 291 }
296 292
297 public List<GridRegion> RequestNamedRegions(string name, int maxNumber) 293 public List<GridRegion> RequestNamedRegions(string name, int maxNumber)
298 { 294 {
299 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); 295 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber);
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index a2ed54f..7eebb99 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -43,6 +43,12 @@ namespace OpenSim.Region.Framework.Scenes
43 43
44 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone); 44 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone);
45 45
46 public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
47
48 public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
49
50 public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
51
46 public delegate void ObjectCreateDelegate(EntityBase obj); 52 public delegate void ObjectCreateDelegate(EntityBase obj);
47 53
48 public delegate void ObjectDeleteDelegate(EntityBase obj); 54 public delegate void ObjectDeleteDelegate(EntityBase obj);
@@ -61,6 +67,9 @@ namespace OpenSim.Region.Framework.Scenes
61 private PhysicsCrash handlerPhysicsCrash = null; 67 private PhysicsCrash handlerPhysicsCrash = null;
62 68
63 public event ObjectDuplicateDelegate OnObjectDuplicate; 69 public event ObjectDuplicateDelegate OnObjectDuplicate;
70 public event AttachToBackupDelegate OnAttachToBackup;
71 public event DetachFromBackupDelegate OnDetachFromBackup;
72 public event ChangedBackupDelegate OnChangeBackup;
64 public event ObjectCreateDelegate OnObjectCreate; 73 public event ObjectCreateDelegate OnObjectCreate;
65 public event ObjectDeleteDelegate OnObjectRemove; 74 public event ObjectDeleteDelegate OnObjectRemove;
66 75
@@ -68,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
68 77
69 #region Fields 78 #region Fields
70 79
71 protected object m_presenceLock = new object(); 80 protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
72 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); 81 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
73 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); 82 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
74 83
@@ -124,13 +133,18 @@ namespace OpenSim.Region.Framework.Scenes
124 133
125 protected internal void Close() 134 protected internal void Close()
126 { 135 {
127 lock (m_presenceLock) 136 m_scenePresencesLock.EnterWriteLock();
137 try
128 { 138 {
129 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 139 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
130 List<ScenePresence> newlist = new List<ScenePresence>(); 140 List<ScenePresence> newlist = new List<ScenePresence>();
131 m_scenePresenceMap = newmap; 141 m_scenePresenceMap = newmap;
132 m_scenePresenceArray = newlist; 142 m_scenePresenceArray = newlist;
133 } 143 }
144 finally
145 {
146 m_scenePresencesLock.ExitWriteLock();
147 }
134 148
135 lock (SceneObjectGroupsByFullID) 149 lock (SceneObjectGroupsByFullID)
136 SceneObjectGroupsByFullID.Clear(); 150 SceneObjectGroupsByFullID.Clear();
@@ -259,6 +273,33 @@ namespace OpenSim.Region.Framework.Scenes
259 protected internal bool AddRestoredSceneObject( 273 protected internal bool AddRestoredSceneObject(
260 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 274 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
261 { 275 {
276 if (!m_parentScene.CombineRegions)
277 {
278 // KF: Check for out-of-region, move inside and make static.
279 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
280 sceneObject.RootPart.GroupPosition.Y,
281 sceneObject.RootPart.GroupPosition.Z);
282 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 ||
283 npos.X > Constants.RegionSize ||
284 npos.Y > Constants.RegionSize))
285 {
286 if (npos.X < 0.0) npos.X = 1.0f;
287 if (npos.Y < 0.0) npos.Y = 1.0f;
288 if (npos.Z < 0.0) npos.Z = 0.0f;
289 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
290 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
291
292 foreach (SceneObjectPart part in sceneObject.Parts)
293 {
294 part.GroupPosition = npos;
295 }
296 sceneObject.RootPart.Velocity = Vector3.Zero;
297 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
298 sceneObject.RootPart.Acceleration = Vector3.Zero;
299 sceneObject.RootPart.Velocity = Vector3.Zero;
300 }
301 }
302
262 if (attachToBackup && (!alreadyPersisted)) 303 if (attachToBackup && (!alreadyPersisted))
263 { 304 {
264 sceneObject.ForceInventoryPersistence(); 305 sceneObject.ForceInventoryPersistence();
@@ -458,6 +499,30 @@ namespace OpenSim.Region.Framework.Scenes
458 m_updateList[obj.UUID] = obj; 499 m_updateList[obj.UUID] = obj;
459 } 500 }
460 501
502 public void FireAttachToBackup(SceneObjectGroup obj)
503 {
504 if (OnAttachToBackup != null)
505 {
506 OnAttachToBackup(obj);
507 }
508 }
509
510 public void FireDetachFromBackup(SceneObjectGroup obj)
511 {
512 if (OnDetachFromBackup != null)
513 {
514 OnDetachFromBackup(obj);
515 }
516 }
517
518 public void FireChangeBackup(SceneObjectGroup obj)
519 {
520 if (OnChangeBackup != null)
521 {
522 OnChangeBackup(obj);
523 }
524 }
525
461 /// <summary> 526 /// <summary>
462 /// Process all pending updates 527 /// Process all pending updates
463 /// </summary> 528 /// </summary>
@@ -592,7 +657,8 @@ namespace OpenSim.Region.Framework.Scenes
592 657
593 Entities[presence.UUID] = presence; 658 Entities[presence.UUID] = presence;
594 659
595 lock (m_presenceLock) 660 m_scenePresencesLock.EnterWriteLock();
661 try
596 { 662 {
597 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 663 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
598 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 664 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -616,6 +682,10 @@ namespace OpenSim.Region.Framework.Scenes
616 m_scenePresenceMap = newmap; 682 m_scenePresenceMap = newmap;
617 m_scenePresenceArray = newlist; 683 m_scenePresenceArray = newlist;
618 } 684 }
685 finally
686 {
687 m_scenePresencesLock.ExitWriteLock();
688 }
619 } 689 }
620 690
621 /// <summary> 691 /// <summary>
@@ -630,7 +700,8 @@ namespace OpenSim.Region.Framework.Scenes
630 agentID); 700 agentID);
631 } 701 }
632 702
633 lock (m_presenceLock) 703 m_scenePresencesLock.EnterWriteLock();
704 try
634 { 705 {
635 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 706 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
636 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 707 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -652,6 +723,10 @@ namespace OpenSim.Region.Framework.Scenes
652 m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 723 m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
653 } 724 }
654 } 725 }
726 finally
727 {
728 m_scenePresencesLock.ExitWriteLock();
729 }
655 } 730 }
656 731
657 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 732 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -775,6 +850,11 @@ namespace OpenSim.Region.Framework.Scenes
775 return m_scenePresenceArray; 850 return m_scenePresenceArray;
776 } 851 }
777 852
853 public int GetNumberOfScenePresences()
854 {
855 return m_scenePresenceArray.Count;
856 }
857
778 /// <summary> 858 /// <summary>
779 /// Request a scene presence by UUID. Fast, indexed lookup. 859 /// Request a scene presence by UUID. Fast, indexed lookup.
780 /// </summary> 860 /// </summary>
@@ -1068,9 +1148,11 @@ namespace OpenSim.Region.Framework.Scenes
1068 /// <param name="action"></param> 1148 /// <param name="action"></param>
1069 protected internal void ForEachSOG(Action<SceneObjectGroup> action) 1149 protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1070 { 1150 {
1071 List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); 1151 EntityBase[] objlist = Entities.GetAllByType<SceneObjectGroup>();
1072 foreach (SceneObjectGroup obj in objlist) 1152 foreach (EntityBase ent in objlist)
1073 { 1153 {
1154 SceneObjectGroup obj = (SceneObjectGroup)ent;
1155
1074 try 1156 try
1075 { 1157 {
1076 action(obj); 1158 action(obj);
@@ -1281,8 +1363,13 @@ namespace OpenSim.Region.Framework.Scenes
1281 { 1363 {
1282 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1364 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1283 { 1365 {
1284 if (m_parentScene.AttachmentsModule != null) 1366 // Set the new attachment point data in the object
1285 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1367 byte attachmentPoint = group.GetAttachmentPoint();
1368 group.UpdateGroupPosition(pos);
1369 group.RootPart.IsAttachment = false;
1370 group.AbsolutePosition = group.RootPart.AttachedPos;
1371 group.SetAttachmentPoint(attachmentPoint);
1372 group.HasGroupChanged = true;
1286 } 1373 }
1287 else 1374 else
1288 { 1375 {
@@ -1526,10 +1613,13 @@ namespace OpenSim.Region.Framework.Scenes
1526 /// <param name="childPrims"></param> 1613 /// <param name="childPrims"></param>
1527 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1614 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1528 { 1615 {
1616 SceneObjectGroup parentGroup = root.ParentGroup;
1617 if (parentGroup == null) return;
1529 Monitor.Enter(m_updateLock); 1618 Monitor.Enter(m_updateLock);
1619
1530 try 1620 try
1531 { 1621 {
1532 SceneObjectGroup parentGroup = root.ParentGroup; 1622 parentGroup.areUpdatesSuspended = true;
1533 1623
1534 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1624 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1535 if (parentGroup != null) 1625 if (parentGroup != null)
@@ -1541,11 +1631,6 @@ namespace OpenSim.Region.Framework.Scenes
1541 1631
1542 if (child != null) 1632 if (child != null)
1543 { 1633 {
1544 // Make sure no child prim is set for sale
1545 // So that, on delink, no prims are unwittingly
1546 // left for sale and sold off
1547 child.RootPart.ObjectSaleType = 0;
1548 child.RootPart.SalePrice = 10;
1549 childGroups.Add(child); 1634 childGroups.Add(child);
1550 } 1635 }
1551 } 1636 }
@@ -1568,12 +1653,13 @@ namespace OpenSim.Region.Framework.Scenes
1568 // occur on link to invoke this elsewhere (such as object selection) 1653 // occur on link to invoke this elsewhere (such as object selection)
1569 parentGroup.RootPart.CreateSelected = true; 1654 parentGroup.RootPart.CreateSelected = true;
1570 parentGroup.TriggerScriptChangedEvent(Changed.LINK); 1655 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1571 parentGroup.HasGroupChanged = true;
1572 parentGroup.ScheduleGroupForFullUpdate();
1573
1574 } 1656 }
1575 finally 1657 finally
1576 { 1658 {
1659 parentGroup.areUpdatesSuspended = false;
1660 parentGroup.HasGroupChanged = true;
1661 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1662 parentGroup.ScheduleGroupForFullUpdate();
1577 Monitor.Exit(m_updateLock); 1663 Monitor.Exit(m_updateLock);
1578 } 1664 }
1579 } 1665 }
@@ -1605,21 +1691,24 @@ namespace OpenSim.Region.Framework.Scenes
1605 1691
1606 SceneObjectGroup group = part.ParentGroup; 1692 SceneObjectGroup group = part.ParentGroup;
1607 if (!affectedGroups.Contains(group)) 1693 if (!affectedGroups.Contains(group))
1694 {
1695 group.areUpdatesSuspended = true;
1608 affectedGroups.Add(group); 1696 affectedGroups.Add(group);
1697 }
1609 } 1698 }
1610 } 1699 }
1611 } 1700 }
1612 1701
1613 foreach (SceneObjectPart child in childParts) 1702 if (childParts.Count > 0)
1614 { 1703 {
1615 // Unlink all child parts from their groups 1704 foreach (SceneObjectPart child in childParts)
1616 // 1705 {
1617 child.ParentGroup.DelinkFromGroup(child, true); 1706 // Unlink all child parts from their groups
1618 1707 //
1619 // These are not in affected groups and will not be 1708 child.ParentGroup.DelinkFromGroup(child, true);
1620 // handled further. Do the honors here. 1709 child.ParentGroup.HasGroupChanged = true;
1621 child.ParentGroup.HasGroupChanged = true; 1710 child.ParentGroup.ScheduleGroupForFullUpdate();
1622 child.ParentGroup.ScheduleGroupForFullUpdate(); 1711 }
1623 } 1712 }
1624 1713
1625 foreach (SceneObjectPart root in rootParts) 1714 foreach (SceneObjectPart root in rootParts)
@@ -1629,56 +1718,68 @@ namespace OpenSim.Region.Framework.Scenes
1629 // However, editing linked parts and unlinking may be different 1718 // However, editing linked parts and unlinking may be different
1630 // 1719 //
1631 SceneObjectGroup group = root.ParentGroup; 1720 SceneObjectGroup group = root.ParentGroup;
1721 group.areUpdatesSuspended = true;
1632 1722
1633 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1723 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1634 int numChildren = newSet.Count; 1724 int numChildren = newSet.Count;
1635 1725
1726 if (numChildren == 1)
1727 break;
1728
1636 // If there are prims left in a link set, but the root is 1729 // If there are prims left in a link set, but the root is
1637 // slated for unlink, we need to do this 1730 // slated for unlink, we need to do this
1731 // Unlink the remaining set
1638 // 1732 //
1639 if (numChildren != 1) 1733 bool sendEventsToRemainder = true;
1640 { 1734 if (numChildren > 1)
1641 // Unlink the remaining set 1735 sendEventsToRemainder = false;
1642 //
1643 bool sendEventsToRemainder = true;
1644 if (numChildren > 1)
1645 sendEventsToRemainder = false;
1646 1736
1647 foreach (SceneObjectPart p in newSet) 1737 foreach (SceneObjectPart p in newSet)
1738 {
1739 if (p != group.RootPart)
1648 { 1740 {
1649 if (p != group.RootPart) 1741 group.DelinkFromGroup(p, sendEventsToRemainder);
1650 group.DelinkFromGroup(p, sendEventsToRemainder); 1742 if (numChildren > 2)
1743 {
1744 p.ParentGroup.areUpdatesSuspended = true;
1745 }
1746 else
1747 {
1748 p.ParentGroup.HasGroupChanged = true;
1749 p.ParentGroup.ScheduleGroupForFullUpdate();
1750 }
1651 } 1751 }
1752 }
1753
1754 // If there is more than one prim remaining, we
1755 // need to re-link
1756 //
1757 if (numChildren > 2)
1758 {
1759 // Remove old root
1760 //
1761 if (newSet.Contains(root))
1762 newSet.Remove(root);
1652 1763
1653 // If there is more than one prim remaining, we 1764 // Preserve link ordering
1654 // need to re-link
1655 // 1765 //
1656 if (numChildren > 2) 1766 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1657 { 1767 {
1658 // Remove old root 1768 return a.LinkNum.CompareTo(b.LinkNum);
1659 // 1769 });
1660 if (newSet.Contains(root))
1661 newSet.Remove(root);
1662
1663 // Preserve link ordering
1664 //
1665 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1666 {
1667 return a.LinkNum.CompareTo(b.LinkNum);
1668 });
1669 1770
1670 // Determine new root 1771 // Determine new root
1671 // 1772 //
1672 SceneObjectPart newRoot = newSet[0]; 1773 SceneObjectPart newRoot = newSet[0];
1673 newSet.RemoveAt(0); 1774 newSet.RemoveAt(0);
1674 1775
1675 foreach (SceneObjectPart newChild in newSet) 1776 foreach (SceneObjectPart newChild in newSet)
1676 newChild.UpdateFlag = 0; 1777 newChild.UpdateFlag = 0;
1677 1778
1678 LinkObjects(newRoot, newSet); 1779 newRoot.ParentGroup.areUpdatesSuspended = true;
1679 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1780 LinkObjects(newRoot, newSet);
1680 affectedGroups.Add(newRoot.ParentGroup); 1781 if (!affectedGroups.Contains(newRoot.ParentGroup))
1681 } 1782 affectedGroups.Add(newRoot.ParentGroup);
1682 } 1783 }
1683 } 1784 }
1684 1785
@@ -1686,8 +1787,14 @@ namespace OpenSim.Region.Framework.Scenes
1686 // 1787 //
1687 foreach (SceneObjectGroup g in affectedGroups) 1788 foreach (SceneObjectGroup g in affectedGroups)
1688 { 1789 {
1790 // Child prims that have been unlinked and deleted will
1791 // return unless the root is deleted. This will remove them
1792 // from the database. They will be rewritten immediately,
1793 // minus the rows for the unlinked child prims.
1794 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1689 g.TriggerScriptChangedEvent(Changed.LINK); 1795 g.TriggerScriptChangedEvent(Changed.LINK);
1690 g.HasGroupChanged = true; // Persist 1796 g.HasGroupChanged = true; // Persist
1797 g.areUpdatesSuspended = false;
1691 g.ScheduleGroupForFullUpdate(); 1798 g.ScheduleGroupForFullUpdate();
1692 } 1799 }
1693 } 1800 }
@@ -1802,9 +1909,6 @@ namespace OpenSim.Region.Framework.Scenes
1802 child.ApplyNextOwnerPermissions(); 1909 child.ApplyNextOwnerPermissions();
1803 } 1910 }
1804 } 1911 }
1805
1806 copy.RootPart.ObjectSaleType = 0;
1807 copy.RootPart.SalePrice = 10;
1808 } 1912 }
1809 1913
1810 Entities.Add(copy); 1914 Entities.Add(copy);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index 982e280..50521c4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -69,10 +69,6 @@ namespace OpenSim.Region.Framework.Scenes
69 /// <summary> 69 /// <summary>
70 /// Stop the scripts contained in all the prims in this group 70 /// Stop the scripts contained in all the prims in this group
71 /// </summary> 71 /// </summary>
72 /// <param name="sceneObjectBeingDeleted">
73 /// Should be true if these scripts are being removed because the scene
74 /// object is being deleted. This will prevent spurious updates to the client.
75 /// </param>
76 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 72 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
77 { 73 {
78 SceneObjectPart[] parts = m_parts.GetArray(); 74 SceneObjectPart[] parts = m_parts.GetArray();
@@ -376,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes
376 372
377 public void ResumeScripts() 373 public void ResumeScripts()
378 { 374 {
375 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
376 return;
377
379 SceneObjectPart[] parts = m_parts.GetArray(); 378 SceneObjectPart[] parts = m_parts.GetArray();
380 for (int i = 0; i < parts.Length; i++) 379 for (int i = 0; i < parts.Length; i++)
381 parts[i].Inventory.ResumeScripts(); 380 parts[i].Inventory.ResumeScripts();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f17fb28..304de67 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 106 /// since the group's last persistent backup
106 /// </summary> 107 /// </summary>
107 private bool m_hasGroupChanged = false; 108 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 109 private long timeFirstChanged = 0;
109 private long timeLastChanged; 110 private long timeLastChanged = 0;
111 private long m_maxPersistTime = 0;
112 private long m_minPersistTime = 0;
113 private Random m_rand;
114 private bool m_suspendUpdates;
115 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
116
117 public bool areUpdatesSuspended
118 {
119 get
120 {
121 return m_suspendUpdates;
122 }
123 set
124 {
125 m_suspendUpdates = value;
126 if (!value)
127 {
128 QueueForUpdateCheck();
129 }
130 }
131 }
110 132
111 public bool HasGroupChanged 133 public bool HasGroupChanged
112 { 134 {
@@ -114,9 +136,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 136 {
115 if (value) 137 if (value)
116 { 138 {
139 if (m_isBackedUp)
140 {
141 m_scene.SceneGraph.FireChangeBackup(this);
142 }
117 timeLastChanged = DateTime.Now.Ticks; 143 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 144 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 145 timeFirstChanged = DateTime.Now.Ticks;
146 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
147 {
148 if (m_rand == null)
149 {
150 byte[] val = new byte[16];
151 m_rootPart.UUID.ToBytes(val, 0);
152 m_rand = new Random(BitConverter.ToInt32(val, 0));
153 }
154
155 if (m_scene.GetRootAgentCount() == 0)
156 {
157 //If the region is empty, this change has been made by an automated process
158 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
159
160 float factor = 1.5f + (float)(m_rand.NextDouble());
161 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
162 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
163 }
164 else
165 {
166 //If the region is not empty, we want to obey the minimum and maximum persist times
167 //but add a random factor so we stagger the object persistance a little
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
170 }
171 }
120 } 172 }
121 m_hasGroupChanged = value; 173 m_hasGroupChanged = value;
122 174
@@ -141,8 +193,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 193 return false;
142 if (m_scene.ShuttingDown) 194 if (m_scene.ShuttingDown)
143 return true; 195 return true;
196
197 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
198 {
199 m_maxPersistTime = m_scene.m_persistAfter;
200 m_minPersistTime = m_scene.m_dontPersistBefore;
201 }
202
144 long currentTime = DateTime.Now.Ticks; 203 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 204
205 if (timeLastChanged == 0) timeLastChanged = currentTime;
206 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
207
208 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 209 return true;
147 return false; 210 return false;
148 } 211 }
@@ -185,10 +248,10 @@ namespace OpenSim.Region.Framework.Scenes
185 248
186 private bool m_scriptListens_atTarget; 249 private bool m_scriptListens_atTarget;
187 private bool m_scriptListens_notAtTarget; 250 private bool m_scriptListens_notAtTarget;
188
189 private bool m_scriptListens_atRotTarget; 251 private bool m_scriptListens_atRotTarget;
190 private bool m_scriptListens_notAtRotTarget; 252 private bool m_scriptListens_notAtRotTarget;
191 253
254 public bool m_dupeInProgress = false;
192 internal Dictionary<UUID, string> m_savedScriptState; 255 internal Dictionary<UUID, string> m_savedScriptState;
193 256
194 #region Properties 257 #region Properties
@@ -228,7 +291,13 @@ namespace OpenSim.Region.Framework.Scenes
228 public virtual Quaternion Rotation 291 public virtual Quaternion Rotation
229 { 292 {
230 get { return m_rotation; } 293 get { return m_rotation; }
231 set { m_rotation = value; } 294 set {
295 foreach(SceneObjectPart p in m_parts.GetArray())
296 {
297 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
298 }
299 m_rotation = value;
300 }
232 } 301 }
233 302
234 public Quaternion GroupRotation 303 public Quaternion GroupRotation
@@ -302,7 +371,11 @@ namespace OpenSim.Region.Framework.Scenes
302 { 371 {
303 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 372 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
304 } 373 }
305 374
375 foreach (SceneObjectPart part in m_parts.GetArray())
376 {
377 part.IgnoreUndoUpdate = true;
378 }
306 if (RootPart.GetStatusSandbox()) 379 if (RootPart.GetStatusSandbox())
307 { 380 {
308 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 381 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -313,10 +386,31 @@ namespace OpenSim.Region.Framework.Scenes
313 return; 386 return;
314 } 387 }
315 } 388 }
316
317 SceneObjectPart[] parts = m_parts.GetArray(); 389 SceneObjectPart[] parts = m_parts.GetArray();
318 for (int i = 0; i < parts.Length; i++) 390 foreach (SceneObjectPart part in parts)
319 parts[i].GroupPosition = val; 391 {
392 part.IgnoreUndoUpdate = false;
393 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
394 part.GroupPosition = val;
395 if (!m_dupeInProgress)
396 {
397 part.TriggerScriptChangedEvent(Changed.POSITION);
398 }
399 }
400 if (!m_dupeInProgress)
401 {
402 foreach (ScenePresence av in m_linkedAvatars)
403 {
404 SceneObjectPart p;
405 if (m_parts.TryGetValue(av.LinkedPrim, out p))
406 {
407 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
408 av.AbsolutePosition += offset;
409 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
410 av.SendAvatarDataToAllAgents();
411 }
412 }
413 }
320 414
321 //if (m_rootPart.PhysActor != null) 415 //if (m_rootPart.PhysActor != null)
322 //{ 416 //{
@@ -467,6 +561,7 @@ namespace OpenSim.Region.Framework.Scenes
467 /// </summary> 561 /// </summary>
468 public SceneObjectGroup() 562 public SceneObjectGroup()
469 { 563 {
564
470 } 565 }
471 566
472 /// <summary> 567 /// <summary>
@@ -483,7 +578,7 @@ namespace OpenSim.Region.Framework.Scenes
483 /// Constructor. This object is added to the scene later via AttachToScene() 578 /// Constructor. This object is added to the scene later via AttachToScene()
484 /// </summary> 579 /// </summary>
485 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 580 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
486 { 581 {
487 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 582 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
488 } 583 }
489 584
@@ -531,6 +626,9 @@ namespace OpenSim.Region.Framework.Scenes
531 /// </summary> 626 /// </summary>
532 public virtual void AttachToBackup() 627 public virtual void AttachToBackup()
533 { 628 {
629 if (IsAttachment) return;
630 m_scene.SceneGraph.FireAttachToBackup(this);
631
534 if (InSceneBackup) 632 if (InSceneBackup)
535 { 633 {
536 //m_log.DebugFormat( 634 //m_log.DebugFormat(
@@ -646,9 +744,9 @@ namespace OpenSim.Region.Framework.Scenes
646 result.normal = inter.normal; 744 result.normal = inter.normal;
647 result.distance = inter.distance; 745 result.distance = inter.distance;
648 } 746 }
747
649 } 748 }
650 } 749 }
651
652 return result; 750 return result;
653 } 751 }
654 752
@@ -668,17 +766,19 @@ namespace OpenSim.Region.Framework.Scenes
668 minZ = 8192f; 766 minZ = 8192f;
669 767
670 SceneObjectPart[] parts = m_parts.GetArray(); 768 SceneObjectPart[] parts = m_parts.GetArray();
671 for (int i = 0; i < parts.Length; i++) 769 foreach (SceneObjectPart part in parts)
672 { 770 {
673 SceneObjectPart part = parts[i];
674
675 Vector3 worldPos = part.GetWorldPosition(); 771 Vector3 worldPos = part.GetWorldPosition();
676 Vector3 offset = worldPos - AbsolutePosition; 772 Vector3 offset = worldPos - AbsolutePosition;
677 Quaternion worldRot; 773 Quaternion worldRot;
678 if (part.ParentID == 0) 774 if (part.ParentID == 0)
775 {
679 worldRot = part.RotationOffset; 776 worldRot = part.RotationOffset;
777 }
680 else 778 else
779 {
681 worldRot = part.GetWorldRotation(); 780 worldRot = part.GetWorldRotation();
781 }
682 782
683 Vector3 frontTopLeft; 783 Vector3 frontTopLeft;
684 Vector3 frontTopRight; 784 Vector3 frontTopRight;
@@ -690,6 +790,8 @@ namespace OpenSim.Region.Framework.Scenes
690 Vector3 backBottomLeft; 790 Vector3 backBottomLeft;
691 Vector3 backBottomRight; 791 Vector3 backBottomRight;
692 792
793 // Vector3[] corners = new Vector3[8];
794
693 Vector3 orig = Vector3.Zero; 795 Vector3 orig = Vector3.Zero;
694 796
695 frontTopLeft.X = orig.X - (part.Scale.X / 2); 797 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -724,6 +826,38 @@ namespace OpenSim.Region.Framework.Scenes
724 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 826 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
725 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 827 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
726 828
829
830
831 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
832 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
833 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
834 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
835 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
836 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
837 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
838 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
839
840 //for (int i = 0; i < 8; i++)
841 //{
842 // corners[i] = corners[i] * worldRot;
843 // corners[i] += offset;
844
845 // if (corners[i].X > maxX)
846 // maxX = corners[i].X;
847 // if (corners[i].X < minX)
848 // minX = corners[i].X;
849
850 // if (corners[i].Y > maxY)
851 // maxY = corners[i].Y;
852 // if (corners[i].Y < minY)
853 // minY = corners[i].Y;
854
855 // if (corners[i].Z > maxZ)
856 // maxZ = corners[i].Y;
857 // if (corners[i].Z < minZ)
858 // minZ = corners[i].Z;
859 //}
860
727 frontTopLeft = frontTopLeft * worldRot; 861 frontTopLeft = frontTopLeft * worldRot;
728 frontTopRight = frontTopRight * worldRot; 862 frontTopRight = frontTopRight * worldRot;
729 frontBottomLeft = frontBottomLeft * worldRot; 863 frontBottomLeft = frontBottomLeft * worldRot;
@@ -745,6 +879,15 @@ namespace OpenSim.Region.Framework.Scenes
745 backTopLeft += offset; 879 backTopLeft += offset;
746 backTopRight += offset; 880 backTopRight += offset;
747 881
882 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
883 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
884 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
885 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
886 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
887 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
888 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
889 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
890
748 if (frontTopRight.X > maxX) 891 if (frontTopRight.X > maxX)
749 maxX = frontTopRight.X; 892 maxX = frontTopRight.X;
750 if (frontTopLeft.X > maxX) 893 if (frontTopLeft.X > maxX)
@@ -890,15 +1033,20 @@ namespace OpenSim.Region.Framework.Scenes
890 1033
891 public void SaveScriptedState(XmlTextWriter writer) 1034 public void SaveScriptedState(XmlTextWriter writer)
892 { 1035 {
1036 SaveScriptedState(writer, false);
1037 }
1038
1039 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1040 {
893 XmlDocument doc = new XmlDocument(); 1041 XmlDocument doc = new XmlDocument();
894 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1042 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
895 1043
896 SceneObjectPart[] parts = m_parts.GetArray(); 1044 SceneObjectPart[] parts = m_parts.GetArray();
897 for (int i = 0; i < parts.Length; i++) 1045 for (int i = 0; i < parts.Length; i++)
898 { 1046 {
899 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1047 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
900 foreach (KeyValuePair<UUID, string> kvp in pstates) 1048 foreach (KeyValuePair<UUID, string> kvp in pstates)
901 states.Add(kvp.Key, kvp.Value); 1049 states[kvp.Key] = kvp.Value;
902 } 1050 }
903 1051
904 if (states.Count > 0) 1052 if (states.Count > 0)
@@ -917,6 +1065,118 @@ namespace OpenSim.Region.Framework.Scenes
917 } 1065 }
918 } 1066 }
919 1067
1068 /// <summary>
1069 /// Add the avatar to this linkset (avatar is sat).
1070 /// </summary>
1071 /// <param name="agentID"></param>
1072 public void AddAvatar(UUID agentID)
1073 {
1074 ScenePresence presence;
1075 if (m_scene.TryGetScenePresence(agentID, out presence))
1076 {
1077 if (!m_linkedAvatars.Contains(presence))
1078 {
1079 m_linkedAvatars.Add(presence);
1080 }
1081 }
1082 }
1083
1084 /// <summary>
1085 /// Delete the avatar from this linkset (avatar is unsat).
1086 /// </summary>
1087 /// <param name="agentID"></param>
1088 public void DeleteAvatar(UUID agentID)
1089 {
1090 ScenePresence presence;
1091 if (m_scene.TryGetScenePresence(agentID, out presence))
1092 {
1093 if (m_linkedAvatars.Contains(presence))
1094 {
1095 m_linkedAvatars.Remove(presence);
1096 }
1097 }
1098 }
1099
1100 /// <summary>
1101 /// Returns the list of linked presences (avatars sat on this group)
1102 /// </summary>
1103 /// <param name="agentID"></param>
1104 public List<ScenePresence> GetLinkedAvatars()
1105 {
1106 return m_linkedAvatars;
1107 }
1108
1109 /// <summary>
1110 /// Attach this scene object to the given avatar.
1111 /// </summary>
1112 /// <param name="agentID"></param>
1113 /// <param name="attachmentpoint"></param>
1114 /// <param name="AttachOffset"></param>
1115 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1116 {
1117 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1118 if (avatar != null)
1119 {
1120 // don't attach attachments to child agents
1121 if (avatar.IsChildAgent) return;
1122
1123// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1124
1125 DetachFromBackup();
1126
1127 // Remove from database and parcel prim count
1128 m_scene.DeleteFromStorage(UUID);
1129 m_scene.EventManager.TriggerParcelPrimCountTainted();
1130
1131 m_rootPart.AttachedAvatar = agentID;
1132
1133 //Anakin Lohner bug #3839
1134 lock (m_parts)
1135 {
1136 foreach (SceneObjectPart p in m_parts.GetArray())
1137 {
1138 p.AttachedAvatar = agentID;
1139 }
1140 }
1141
1142 if (m_rootPart.PhysActor != null)
1143 {
1144 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1145 m_rootPart.PhysActor = null;
1146 }
1147
1148 AbsolutePosition = AttachOffset;
1149 m_rootPart.AttachedPos = AttachOffset;
1150 m_rootPart.IsAttachment = true;
1151
1152 m_rootPart.SetParentLocalId(avatar.LocalId);
1153 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1154
1155 avatar.AddAttachment(this);
1156
1157 if (!silent)
1158 {
1159 // Killing it here will cause the client to deselect it
1160 // It then reappears on the avatar, deselected
1161 // through the full update below
1162 //
1163 if (IsSelected)
1164 {
1165 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1166 }
1167
1168 IsSelected = false; // fudge....
1169 ScheduleGroupForFullUpdate();
1170 }
1171 }
1172 else
1173 {
1174 m_log.WarnFormat(
1175 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1176 UUID, agentID, Scene.RegionInfo.RegionName);
1177 }
1178 }
1179
920 public byte GetAttachmentPoint() 1180 public byte GetAttachmentPoint()
921 { 1181 {
922 return m_rootPart.Shape.State; 1182 return m_rootPart.Shape.State;
@@ -1043,7 +1303,10 @@ namespace OpenSim.Region.Framework.Scenes
1043 public void AddPart(SceneObjectPart part) 1303 public void AddPart(SceneObjectPart part)
1044 { 1304 {
1045 part.SetParent(this); 1305 part.SetParent(this);
1046 part.LinkNum = m_parts.Add(part.UUID, part); 1306 m_parts.Add(part.UUID, part);
1307
1308 part.LinkNum = m_parts.Count;
1309
1047 if (part.LinkNum == 2 && RootPart != null) 1310 if (part.LinkNum == 2 && RootPart != null)
1048 RootPart.LinkNum = 1; 1311 RootPart.LinkNum = 1;
1049 } 1312 }
@@ -1127,7 +1390,7 @@ namespace OpenSim.Region.Framework.Scenes
1127 1390
1128 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1391 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1129 { 1392 {
1130 part.StoreUndoState(); 1393 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1131 part.OnGrab(offsetPos, remoteClient); 1394 part.OnGrab(offsetPos, remoteClient);
1132 } 1395 }
1133 1396
@@ -1147,6 +1410,11 @@ namespace OpenSim.Region.Framework.Scenes
1147 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1410 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1148 public void DeleteGroupFromScene(bool silent) 1411 public void DeleteGroupFromScene(bool silent)
1149 { 1412 {
1413 // We need to keep track of this state in case this group is still queued for backup.
1414 m_isDeleted = true;
1415
1416 DetachFromBackup();
1417
1150 SceneObjectPart[] parts = m_parts.GetArray(); 1418 SceneObjectPart[] parts = m_parts.GetArray();
1151 for (int i = 0; i < parts.Length; i++) 1419 for (int i = 0; i < parts.Length; i++)
1152 { 1420 {
@@ -1158,13 +1426,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 avatar.StandUp(); 1426 avatar.StandUp();
1159 1427
1160 if (!silent) 1428 if (!silent)
1161 {
1162 part.UpdateFlag = 0; 1429 part.UpdateFlag = 0;
1163 if (part == m_rootPart)
1164 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1165 }
1166 }); 1430 });
1167 } 1431 }
1432
1433
1168 } 1434 }
1169 1435
1170 public void AddScriptLPS(int count) 1436 public void AddScriptLPS(int count)
@@ -1261,7 +1527,12 @@ namespace OpenSim.Region.Framework.Scenes
1261 1527
1262 public void SetOwnerId(UUID userId) 1528 public void SetOwnerId(UUID userId)
1263 { 1529 {
1264 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1530 ForEachPart(delegate(SceneObjectPart part)
1531 {
1532
1533 part.OwnerID = userId;
1534
1535 });
1265 } 1536 }
1266 1537
1267 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1538 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1293,11 +1564,17 @@ namespace OpenSim.Region.Framework.Scenes
1293 return; 1564 return;
1294 } 1565 }
1295 1566
1567 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1568 return;
1569
1296 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1570 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1297 // any exception propogate upwards. 1571 // any exception propogate upwards.
1298 try 1572 try
1299 { 1573 {
1300 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1574 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1575 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1576 m_scene.LoadingPrims) // Land may not be valid yet
1577
1301 { 1578 {
1302 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1579 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1303 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1580 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1322,6 +1599,7 @@ namespace OpenSim.Region.Framework.Scenes
1322 } 1599 }
1323 } 1600 }
1324 } 1601 }
1602
1325 } 1603 }
1326 1604
1327 if (HasGroupChanged) 1605 if (HasGroupChanged)
@@ -1329,6 +1607,20 @@ namespace OpenSim.Region.Framework.Scenes
1329 // don't backup while it's selected or you're asking for changes mid stream. 1607 // don't backup while it's selected or you're asking for changes mid stream.
1330 if (isTimeToPersist() || forcedBackup) 1608 if (isTimeToPersist() || forcedBackup)
1331 { 1609 {
1610 if (m_rootPart.PhysActor != null &&
1611 (!m_rootPart.PhysActor.IsPhysical))
1612 {
1613 // Possible ghost prim
1614 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1615 {
1616 foreach (SceneObjectPart part in m_parts.GetArray())
1617 {
1618 // Re-set physics actor positions and
1619 // orientations
1620 part.GroupPosition = m_rootPart.GroupPosition;
1621 }
1622 }
1623 }
1332// m_log.DebugFormat( 1624// m_log.DebugFormat(
1333// "[SCENE]: Storing {0}, {1} in {2}", 1625// "[SCENE]: Storing {0}, {1} in {2}",
1334// Name, UUID, m_scene.RegionInfo.RegionName); 1626// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1392,81 +1684,90 @@ namespace OpenSim.Region.Framework.Scenes
1392 /// <returns></returns> 1684 /// <returns></returns>
1393 public SceneObjectGroup Copy(bool userExposed) 1685 public SceneObjectGroup Copy(bool userExposed)
1394 { 1686 {
1395 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1687 SceneObjectGroup dupe;
1396 dupe.m_isBackedUp = false; 1688 try
1397 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1689 {
1398 1690 m_dupeInProgress = true;
1399 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1691 dupe = (SceneObjectGroup)MemberwiseClone();
1400 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1692 dupe.m_isBackedUp = false;
1401 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1693 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1402 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1403 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1404 // then restore it's attachment state
1405
1406 // This is only necessary when userExposed is false!
1407 1694
1408 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1695 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1409 1696 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1410 if (!userExposed) 1697 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1411 dupe.RootPart.IsAttachment = true; 1698 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1699 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1700 // then restore it's attachment state
1412 1701
1413 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1702 // This is only necessary when userExposed is false!
1414 1703
1415 if (!userExposed) 1704 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1416 {
1417 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1418 }
1419 1705
1420 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1706 if (!userExposed)
1421 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1707 dupe.RootPart.IsAttachment = true;
1422 1708
1423 if (userExposed) 1709 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1424 dupe.m_rootPart.TrimPermissions();
1425 1710
1426 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1711 if (!userExposed)
1427
1428 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1429 { 1712 {
1430 return p1.LinkNum.CompareTo(p2.LinkNum); 1713 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1431 } 1714 }
1432 );
1433 1715
1434 foreach (SceneObjectPart part in partList) 1716 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1435 { 1717 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1436 if (part.UUID != m_rootPart.UUID) 1718
1719 if (userExposed)
1720 dupe.m_rootPart.TrimPermissions();
1721
1722 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1723
1724 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1725 {
1726 return p1.LinkNum.CompareTo(p2.LinkNum);
1727 }
1728 );
1729
1730 foreach (SceneObjectPart part in partList)
1437 { 1731 {
1438 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1732 if (part.UUID != m_rootPart.UUID)
1439 newPart.LinkNum = part.LinkNum; 1733 {
1440 } 1734 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1735
1736 newPart.LinkNum = part.LinkNum;
1737 }
1441 1738
1442 // Need to duplicate the physics actor as well 1739 // Need to duplicate the physics actor as well
1443 if (part.PhysActor != null && userExposed) 1740 if (part.PhysActor != null && userExposed)
1741 {
1742 PrimitiveBaseShape pbs = part.Shape;
1743
1744 part.PhysActor
1745 = m_scene.PhysicsScene.AddPrimShape(
1746 string.Format("{0}/{1}", part.Name, part.UUID),
1747 pbs,
1748 part.AbsolutePosition,
1749 part.Scale,
1750 part.RotationOffset,
1751 part.PhysActor.IsPhysical);
1752 part.PhysActor.SetMaterial((int)part.Material);
1753
1754 part.PhysActor.LocalID = part.LocalId;
1755 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1756 }
1757 }
1758 if (userExposed)
1444 { 1759 {
1445 PrimitiveBaseShape pbs = part.Shape; 1760 dupe.UpdateParentIDs();
1446 1761 dupe.HasGroupChanged = true;
1447 part.PhysActor 1762 dupe.AttachToBackup();
1448 = m_scene.PhysicsScene.AddPrimShape( 1763
1449 string.Format("{0}/{1}", part.Name, part.UUID), 1764 ScheduleGroupForFullUpdate();
1450 pbs,
1451 part.AbsolutePosition,
1452 part.Scale,
1453 part.RotationOffset,
1454 part.PhysActor.IsPhysical);
1455
1456 part.PhysActor.LocalID = part.LocalId;
1457 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1458 } 1765 }
1459 } 1766 }
1460 1767 finally
1461 if (userExposed)
1462 { 1768 {
1463 dupe.UpdateParentIDs(); 1769 m_dupeInProgress = false;
1464 dupe.HasGroupChanged = true;
1465 dupe.AttachToBackup();
1466
1467 ScheduleGroupForFullUpdate();
1468 } 1770 }
1469
1470 return dupe; 1771 return dupe;
1471 } 1772 }
1472 1773
@@ -1657,13 +1958,40 @@ namespace OpenSim.Region.Framework.Scenes
1657 } 1958 }
1658 } 1959 }
1659 1960
1961 public void rotLookAt(Quaternion target, float strength, float damping)
1962 {
1963 SceneObjectPart rootpart = m_rootPart;
1964 if (rootpart != null)
1965 {
1966 if (IsAttachment)
1967 {
1968 /*
1969 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1970 if (avatar != null)
1971 {
1972 Rotate the Av?
1973 } */
1974 }
1975 else
1976 {
1977 if (rootpart.PhysActor != null)
1978 { // APID must be implemented in your physics system for this to function.
1979 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1980 rootpart.PhysActor.APIDStrength = strength;
1981 rootpart.PhysActor.APIDDamping = damping;
1982 rootpart.PhysActor.APIDActive = true;
1983 }
1984 }
1985 }
1986 }
1987
1660 public void stopLookAt() 1988 public void stopLookAt()
1661 { 1989 {
1662 SceneObjectPart rootpart = m_rootPart; 1990 SceneObjectPart rootpart = m_rootPart;
1663 if (rootpart != null) 1991 if (rootpart != null)
1664 { 1992 {
1665 if (rootpart.PhysActor != null) 1993 if (rootpart.PhysActor != null)
1666 { 1994 { // APID must be implemented in your physics system for this to function.
1667 rootpart.PhysActor.APIDActive = false; 1995 rootpart.PhysActor.APIDActive = false;
1668 } 1996 }
1669 } 1997 }
@@ -1729,6 +2057,8 @@ namespace OpenSim.Region.Framework.Scenes
1729 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2057 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1730 { 2058 {
1731 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2059 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2060 newPart.SetParent(this);
2061
1732 AddPart(newPart); 2062 AddPart(newPart);
1733 2063
1734 SetPartAsNonRoot(newPart); 2064 SetPartAsNonRoot(newPart);
@@ -1875,11 +2205,11 @@ namespace OpenSim.Region.Framework.Scenes
1875 /// Immediately send a full update for this scene object. 2205 /// Immediately send a full update for this scene object.
1876 /// </summary> 2206 /// </summary>
1877 public void SendGroupFullUpdate() 2207 public void SendGroupFullUpdate()
1878 { 2208 {
1879 if (IsDeleted) 2209 if (IsDeleted)
1880 return; 2210 return;
1881 2211
1882// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2212// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1883 2213
1884 RootPart.SendFullUpdateToAllClients(); 2214 RootPart.SendFullUpdateToAllClients();
1885 2215
@@ -2068,12 +2398,15 @@ namespace OpenSim.Region.Framework.Scenes
2068 part.LinkNum += objectGroup.PrimCount; 2398 part.LinkNum += objectGroup.PrimCount;
2069 } 2399 }
2070 } 2400 }
2401 }
2071 2402
2072 linkPart.LinkNum = 2; 2403 linkPart.LinkNum = 2;
2073 2404
2074 linkPart.SetParent(this); 2405 linkPart.SetParent(this);
2075 linkPart.CreateSelected = true; 2406 linkPart.CreateSelected = true;
2076 2407
2408 lock (m_parts.SyncRoot)
2409 {
2077 //if (linkPart.PhysActor != null) 2410 //if (linkPart.PhysActor != null)
2078 //{ 2411 //{
2079 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2412 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2231,6 +2564,8 @@ namespace OpenSim.Region.Framework.Scenes
2231 /// <param name="objectGroup"></param> 2564 /// <param name="objectGroup"></param>
2232 public virtual void DetachFromBackup() 2565 public virtual void DetachFromBackup()
2233 { 2566 {
2567 m_scene.SceneGraph.FireDetachFromBackup(this);
2568
2234 if (m_isBackedUp) 2569 if (m_isBackedUp)
2235 m_scene.EventManager.OnBackup -= ProcessBackup; 2570 m_scene.EventManager.OnBackup -= ProcessBackup;
2236 2571
@@ -2249,7 +2584,8 @@ namespace OpenSim.Region.Framework.Scenes
2249 2584
2250 axPos *= parentRot; 2585 axPos *= parentRot;
2251 part.OffsetPosition = axPos; 2586 part.OffsetPosition = axPos;
2252 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2587 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2588 part.GroupPosition = newPos;
2253 part.OffsetPosition = Vector3.Zero; 2589 part.OffsetPosition = Vector3.Zero;
2254 part.RotationOffset = worldRot; 2590 part.RotationOffset = worldRot;
2255 2591
@@ -2260,7 +2596,7 @@ namespace OpenSim.Region.Framework.Scenes
2260 2596
2261 part.LinkNum = linkNum; 2597 part.LinkNum = linkNum;
2262 2598
2263 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2599 part.OffsetPosition = newPos - AbsolutePosition;
2264 2600
2265 Quaternion rootRotation = m_rootPart.RotationOffset; 2601 Quaternion rootRotation = m_rootPart.RotationOffset;
2266 2602
@@ -2270,7 +2606,7 @@ namespace OpenSim.Region.Framework.Scenes
2270 2606
2271 parentRot = m_rootPart.RotationOffset; 2607 parentRot = m_rootPart.RotationOffset;
2272 oldRot = part.RotationOffset; 2608 oldRot = part.RotationOffset;
2273 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2609 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2274 part.RotationOffset = newRot; 2610 part.RotationOffset = newRot;
2275 } 2611 }
2276 2612
@@ -2535,6 +2871,17 @@ namespace OpenSim.Region.Framework.Scenes
2535 } 2871 }
2536 } 2872 }
2537 2873
2874
2875
2876 /// <summary>
2877 /// Gets the number of parts
2878 /// </summary>
2879 /// <returns></returns>
2880 public int GetPartCount()
2881 {
2882 return Parts.Count();
2883 }
2884
2538 /// <summary> 2885 /// <summary>
2539 /// Update the texture entry for this part 2886 /// Update the texture entry for this part
2540 /// </summary> 2887 /// </summary>
@@ -2596,11 +2943,9 @@ namespace OpenSim.Region.Framework.Scenes
2596 scale.Y = m_scene.m_maxNonphys; 2943 scale.Y = m_scene.m_maxNonphys;
2597 if (scale.Z > m_scene.m_maxNonphys) 2944 if (scale.Z > m_scene.m_maxNonphys)
2598 scale.Z = m_scene.m_maxNonphys; 2945 scale.Z = m_scene.m_maxNonphys;
2599
2600 SceneObjectPart part = GetChildPart(localID); 2946 SceneObjectPart part = GetChildPart(localID);
2601 if (part != null) 2947 if (part != null)
2602 { 2948 {
2603 part.Resize(scale);
2604 if (part.PhysActor != null) 2949 if (part.PhysActor != null)
2605 { 2950 {
2606 if (part.PhysActor.IsPhysical) 2951 if (part.PhysActor.IsPhysical)
@@ -2615,7 +2960,7 @@ namespace OpenSim.Region.Framework.Scenes
2615 part.PhysActor.Size = scale; 2960 part.PhysActor.Size = scale;
2616 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2961 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2617 } 2962 }
2618 //if (part.UUID != m_rootPart.UUID) 2963 part.Resize(scale);
2619 2964
2620 HasGroupChanged = true; 2965 HasGroupChanged = true;
2621 part.TriggerScriptChangedEvent(Changed.SCALE); 2966 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2638,7 +2983,6 @@ namespace OpenSim.Region.Framework.Scenes
2638 SceneObjectPart part = GetChildPart(localID); 2983 SceneObjectPart part = GetChildPart(localID);
2639 if (part != null) 2984 if (part != null)
2640 { 2985 {
2641 part.IgnoreUndoUpdate = true;
2642 if (scale.X > m_scene.m_maxNonphys) 2986 if (scale.X > m_scene.m_maxNonphys)
2643 scale.X = m_scene.m_maxNonphys; 2987 scale.X = m_scene.m_maxNonphys;
2644 if (scale.Y > m_scene.m_maxNonphys) 2988 if (scale.Y > m_scene.m_maxNonphys)
@@ -2675,7 +3019,7 @@ namespace OpenSim.Region.Framework.Scenes
2675 3019
2676 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3020 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2677 { 3021 {
2678 if (oldSize.X * x > m_scene.m_maxPhys) 3022 if (oldSize.X*x > m_scene.m_maxPhys)
2679 { 3023 {
2680 f = m_scene.m_maxPhys / oldSize.X; 3024 f = m_scene.m_maxPhys / oldSize.X;
2681 a = f / x; 3025 a = f / x;
@@ -2683,7 +3027,7 @@ namespace OpenSim.Region.Framework.Scenes
2683 y *= a; 3027 y *= a;
2684 z *= a; 3028 z *= a;
2685 } 3029 }
2686 if (oldSize.Y * y > m_scene.m_maxPhys) 3030 if (oldSize.Y*y > m_scene.m_maxPhys)
2687 { 3031 {
2688 f = m_scene.m_maxPhys / oldSize.Y; 3032 f = m_scene.m_maxPhys / oldSize.Y;
2689 a = f / y; 3033 a = f / y;
@@ -2691,7 +3035,7 @@ namespace OpenSim.Region.Framework.Scenes
2691 y *= a; 3035 y *= a;
2692 z *= a; 3036 z *= a;
2693 } 3037 }
2694 if (oldSize.Z * z > m_scene.m_maxPhys) 3038 if (oldSize.Z*z > m_scene.m_maxPhys)
2695 { 3039 {
2696 f = m_scene.m_maxPhys / oldSize.Z; 3040 f = m_scene.m_maxPhys / oldSize.Z;
2697 a = f / z; 3041 a = f / z;
@@ -2702,7 +3046,7 @@ namespace OpenSim.Region.Framework.Scenes
2702 } 3046 }
2703 else 3047 else
2704 { 3048 {
2705 if (oldSize.X * x > m_scene.m_maxNonphys) 3049 if (oldSize.X*x > m_scene.m_maxNonphys)
2706 { 3050 {
2707 f = m_scene.m_maxNonphys / oldSize.X; 3051 f = m_scene.m_maxNonphys / oldSize.X;
2708 a = f / x; 3052 a = f / x;
@@ -2710,7 +3054,7 @@ namespace OpenSim.Region.Framework.Scenes
2710 y *= a; 3054 y *= a;
2711 z *= a; 3055 z *= a;
2712 } 3056 }
2713 if (oldSize.Y * y > m_scene.m_maxNonphys) 3057 if (oldSize.Y*y > m_scene.m_maxNonphys)
2714 { 3058 {
2715 f = m_scene.m_maxNonphys / oldSize.Y; 3059 f = m_scene.m_maxNonphys / oldSize.Y;
2716 a = f / y; 3060 a = f / y;
@@ -2718,7 +3062,7 @@ namespace OpenSim.Region.Framework.Scenes
2718 y *= a; 3062 y *= a;
2719 z *= a; 3063 z *= a;
2720 } 3064 }
2721 if (oldSize.Z * z > m_scene.m_maxNonphys) 3065 if (oldSize.Z*z > m_scene.m_maxNonphys)
2722 { 3066 {
2723 f = m_scene.m_maxNonphys / oldSize.Z; 3067 f = m_scene.m_maxNonphys / oldSize.Z;
2724 a = f / z; 3068 a = f / z;
@@ -2728,7 +3072,6 @@ namespace OpenSim.Region.Framework.Scenes
2728 } 3072 }
2729 } 3073 }
2730 obPart.IgnoreUndoUpdate = false; 3074 obPart.IgnoreUndoUpdate = false;
2731 obPart.StoreUndoState();
2732 } 3075 }
2733 } 3076 }
2734 } 3077 }
@@ -2736,8 +3079,13 @@ namespace OpenSim.Region.Framework.Scenes
2736 Vector3 prevScale = part.Scale; 3079 Vector3 prevScale = part.Scale;
2737 prevScale.X *= x; 3080 prevScale.X *= x;
2738 prevScale.Y *= y; 3081 prevScale.Y *= y;
2739 prevScale.Z *= z; 3082 prevScale.Z *= z;;
3083
3084 part.IgnoreUndoUpdate = false;
3085 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3086 part.IgnoreUndoUpdate = true;
2740 part.Resize(prevScale); 3087 part.Resize(prevScale);
3088 part.IgnoreUndoUpdate = false;
2741 3089
2742 parts = m_parts.GetArray(); 3090 parts = m_parts.GetArray();
2743 for (int i = 0; i < parts.Length; i++) 3091 for (int i = 0; i < parts.Length; i++)
@@ -2746,19 +3094,26 @@ namespace OpenSim.Region.Framework.Scenes
2746 obPart.IgnoreUndoUpdate = true; 3094 obPart.IgnoreUndoUpdate = true;
2747 if (obPart.UUID != m_rootPart.UUID) 3095 if (obPart.UUID != m_rootPart.UUID)
2748 { 3096 {
2749 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3097 if (obPart.UUID != m_rootPart.UUID)
2750 currentpos.X *= x; 3098 {
2751 currentpos.Y *= y; 3099 obPart.IgnoreUndoUpdate = false;
2752 currentpos.Z *= z; 3100 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2753 Vector3 newSize = new Vector3(obPart.Scale); 3101 obPart.IgnoreUndoUpdate = true;
2754 newSize.X *= x; 3102
2755 newSize.Y *= y; 3103 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2756 newSize.Z *= z; 3104 currentpos.X *= x;
2757 obPart.Resize(newSize); 3105 currentpos.Y *= y;
2758 obPart.UpdateOffSet(currentpos); 3106 currentpos.Z *= z;
3107 Vector3 newSize = new Vector3(obPart.Scale);
3108 newSize.X *= x;
3109 newSize.Y *= y;
3110 newSize.Z *= z;
3111 obPart.Resize(newSize);
3112 obPart.UpdateOffSet(currentpos);
3113 }
3114 obPart.IgnoreUndoUpdate = false;
2759 } 3115 }
2760 obPart.IgnoreUndoUpdate = false; 3116 obPart.IgnoreUndoUpdate = false;
2761 obPart.StoreUndoState();
2762 } 3117 }
2763 3118
2764 if (part.PhysActor != null) 3119 if (part.PhysActor != null)
@@ -2768,7 +3123,6 @@ namespace OpenSim.Region.Framework.Scenes
2768 } 3123 }
2769 3124
2770 part.IgnoreUndoUpdate = false; 3125 part.IgnoreUndoUpdate = false;
2771 part.StoreUndoState();
2772 HasGroupChanged = true; 3126 HasGroupChanged = true;
2773 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3127 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2774 ScheduleGroupForTerseUpdate(); 3128 ScheduleGroupForTerseUpdate();
@@ -2785,14 +3139,11 @@ namespace OpenSim.Region.Framework.Scenes
2785 /// <param name="pos"></param> 3139 /// <param name="pos"></param>
2786 public void UpdateGroupPosition(Vector3 pos) 3140 public void UpdateGroupPosition(Vector3 pos)
2787 { 3141 {
2788 SceneObjectPart[] parts = m_parts.GetArray();
2789 for (int i = 0; i < parts.Length; i++)
2790 parts[i].StoreUndoState();
2791
2792 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3142 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2793 { 3143 {
2794 if (IsAttachment) 3144 if (IsAttachment)
2795 { 3145 {
3146 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2796 m_rootPart.AttachedPos = pos; 3147 m_rootPart.AttachedPos = pos;
2797 } 3148 }
2798 if (RootPart.GetStatusSandbox()) 3149 if (RootPart.GetStatusSandbox())
@@ -2826,7 +3177,7 @@ namespace OpenSim.Region.Framework.Scenes
2826 3177
2827 SceneObjectPart[] parts = m_parts.GetArray(); 3178 SceneObjectPart[] parts = m_parts.GetArray();
2828 for (int i = 0; i < parts.Length; i++) 3179 for (int i = 0; i < parts.Length; i++)
2829 parts[i].StoreUndoState(); 3180 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2830 3181
2831 if (part != null) 3182 if (part != null)
2832 { 3183 {
@@ -2851,7 +3202,7 @@ namespace OpenSim.Region.Framework.Scenes
2851 { 3202 {
2852 SceneObjectPart[] parts = m_parts.GetArray(); 3203 SceneObjectPart[] parts = m_parts.GetArray();
2853 for (int i = 0; i < parts.Length; i++) 3204 for (int i = 0; i < parts.Length; i++)
2854 parts[i].StoreUndoState(); 3205 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2855 3206
2856 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3207 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2857 Vector3 oldPos = 3208 Vector3 oldPos =
@@ -2872,10 +3223,27 @@ namespace OpenSim.Region.Framework.Scenes
2872 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3223 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2873 } 3224 }
2874 3225
2875 AbsolutePosition = newPos; 3226 //We have to set undoing here because otherwise an undo state will be saved
3227 if (!m_rootPart.Undoing)
3228 {
3229 m_rootPart.Undoing = true;
3230 AbsolutePosition = newPos;
3231 m_rootPart.Undoing = false;
3232 }
3233 else
3234 {
3235 AbsolutePosition = newPos;
3236 }
2876 3237
2877 HasGroupChanged = true; 3238 HasGroupChanged = true;
2878 ScheduleGroupForTerseUpdate(); 3239 if (m_rootPart.Undoing)
3240 {
3241 ScheduleGroupForFullUpdate();
3242 }
3243 else
3244 {
3245 ScheduleGroupForTerseUpdate();
3246 }
2879 } 3247 }
2880 3248
2881 public void OffsetForNewRegion(Vector3 offset) 3249 public void OffsetForNewRegion(Vector3 offset)
@@ -2895,7 +3263,7 @@ namespace OpenSim.Region.Framework.Scenes
2895 { 3263 {
2896 SceneObjectPart[] parts = m_parts.GetArray(); 3264 SceneObjectPart[] parts = m_parts.GetArray();
2897 for (int i = 0; i < parts.Length; i++) 3265 for (int i = 0; i < parts.Length; i++)
2898 parts[i].StoreUndoState(); 3266 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2899 3267
2900 m_rootPart.UpdateRotation(rot); 3268 m_rootPart.UpdateRotation(rot);
2901 3269
@@ -2919,7 +3287,7 @@ namespace OpenSim.Region.Framework.Scenes
2919 { 3287 {
2920 SceneObjectPart[] parts = m_parts.GetArray(); 3288 SceneObjectPart[] parts = m_parts.GetArray();
2921 for (int i = 0; i < parts.Length; i++) 3289 for (int i = 0; i < parts.Length; i++)
2922 parts[i].StoreUndoState(); 3290 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2923 3291
2924 m_rootPart.UpdateRotation(rot); 3292 m_rootPart.UpdateRotation(rot);
2925 3293
@@ -2944,10 +3312,9 @@ namespace OpenSim.Region.Framework.Scenes
2944 public void UpdateSingleRotation(Quaternion rot, uint localID) 3312 public void UpdateSingleRotation(Quaternion rot, uint localID)
2945 { 3313 {
2946 SceneObjectPart part = GetChildPart(localID); 3314 SceneObjectPart part = GetChildPart(localID);
2947
2948 SceneObjectPart[] parts = m_parts.GetArray(); 3315 SceneObjectPart[] parts = m_parts.GetArray();
2949 for (int i = 0; i < parts.Length; i++) 3316 for (int i = 0; i < parts.Length; i++)
2950 parts[i].StoreUndoState(); 3317 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2951 3318
2952 if (part != null) 3319 if (part != null)
2953 { 3320 {
@@ -2975,15 +3342,24 @@ namespace OpenSim.Region.Framework.Scenes
2975 if (part.UUID == m_rootPart.UUID) 3342 if (part.UUID == m_rootPart.UUID)
2976 { 3343 {
2977 UpdateRootRotation(rot); 3344 UpdateRootRotation(rot);
2978 AbsolutePosition = pos; 3345 if (!m_rootPart.Undoing)
3346 {
3347 m_rootPart.Undoing = true;
3348 AbsolutePosition = pos;
3349 m_rootPart.Undoing = false;
3350 }
3351 else
3352 {
3353 AbsolutePosition = pos;
3354 }
2979 } 3355 }
2980 else 3356 else
2981 { 3357 {
3358 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2982 part.IgnoreUndoUpdate = true; 3359 part.IgnoreUndoUpdate = true;
2983 part.UpdateRotation(rot); 3360 part.UpdateRotation(rot);
2984 part.OffsetPosition = pos; 3361 part.OffsetPosition = pos;
2985 part.IgnoreUndoUpdate = false; 3362 part.IgnoreUndoUpdate = false;
2986 part.StoreUndoState();
2987 } 3363 }
2988 } 3364 }
2989 } 3365 }
@@ -2997,7 +3373,13 @@ namespace OpenSim.Region.Framework.Scenes
2997 Quaternion axRot = rot; 3373 Quaternion axRot = rot;
2998 Quaternion oldParentRot = m_rootPart.RotationOffset; 3374 Quaternion oldParentRot = m_rootPart.RotationOffset;
2999 3375
3000 m_rootPart.StoreUndoState(); 3376 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3377 bool cancelUndo = false;
3378 if (!m_rootPart.Undoing)
3379 {
3380 m_rootPart.Undoing = true;
3381 cancelUndo = true;
3382 }
3001 m_rootPart.UpdateRotation(rot); 3383 m_rootPart.UpdateRotation(rot);
3002 if (m_rootPart.PhysActor != null) 3384 if (m_rootPart.PhysActor != null)
3003 { 3385 {
@@ -3021,17 +3403,12 @@ namespace OpenSim.Region.Framework.Scenes
3021 newRot *= Quaternion.Inverse(axRot); 3403 newRot *= Quaternion.Inverse(axRot);
3022 prim.RotationOffset = newRot; 3404 prim.RotationOffset = newRot;
3023 prim.ScheduleTerseUpdate(); 3405 prim.ScheduleTerseUpdate();
3406 prim.IgnoreUndoUpdate = false;
3024 } 3407 }
3025 } 3408 }
3026 3409 if (cancelUndo == true)
3027 for (int i = 0; i < parts.Length; i++)
3028 { 3410 {
3029 SceneObjectPart childpart = parts[i]; 3411 m_rootPart.Undoing = false;
3030 if (childpart != m_rootPart)
3031 {
3032 childpart.IgnoreUndoUpdate = false;
3033 childpart.StoreUndoState();
3034 }
3035 } 3412 }
3036 3413
3037 m_rootPart.ScheduleTerseUpdate(); 3414 m_rootPart.ScheduleTerseUpdate();
@@ -3257,7 +3634,6 @@ namespace OpenSim.Region.Framework.Scenes
3257 public float GetMass() 3634 public float GetMass()
3258 { 3635 {
3259 float retmass = 0f; 3636 float retmass = 0f;
3260
3261 SceneObjectPart[] parts = m_parts.GetArray(); 3637 SceneObjectPart[] parts = m_parts.GetArray();
3262 for (int i = 0; i < parts.Length; i++) 3638 for (int i = 0; i < parts.Length; i++)
3263 retmass += parts[i].GetMass(); 3639 retmass += parts[i].GetMass();
@@ -3373,6 +3749,14 @@ namespace OpenSim.Region.Framework.Scenes
3373 SetFromItemID(uuid); 3749 SetFromItemID(uuid);
3374 } 3750 }
3375 3751
3752 public void ResetOwnerChangeFlag()
3753 {
3754 ForEachPart(delegate(SceneObjectPart part)
3755 {
3756 part.ResetOwnerChangeFlag();
3757 });
3758 }
3759
3376 #endregion 3760 #endregion
3377 } 3761 }
3378} 3762}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 4fcd8f5..6496a25 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -61,7 +61,8 @@ namespace OpenSim.Region.Framework.Scenes
61 TELEPORT = 512, 61 TELEPORT = 512,
62 REGION_RESTART = 1024, 62 REGION_RESTART = 1024,
63 MEDIA = 2048, 63 MEDIA = 2048,
64 ANIMATION = 16384 64 ANIMATION = 16384,
65 POSITION = 32768
65 } 66 }
66 67
67 // I don't really know where to put this except here. 68 // I don't really know where to put this except here.
@@ -145,10 +146,10 @@ namespace OpenSim.Region.Framework.Scenes
145 public Vector3 StatusSandboxPos; 146 public Vector3 StatusSandboxPos;
146 147
147 // TODO: This needs to be persisted in next XML version update! 148 // TODO: This needs to be persisted in next XML version update!
148 149 [XmlIgnore]
149 public readonly int[] PayPrice = {-2,-2,-2,-2,-2}; 150 public int[] PayPrice = {-2,-2,-2,-2,-2};
150 151
151 152 [XmlIgnore]
152 public PhysicsActor PhysActor 153 public PhysicsActor PhysActor
153 { 154 {
154 get { return m_physActor; } 155 get { return m_physActor; }
@@ -190,7 +191,15 @@ namespace OpenSim.Region.Framework.Scenes
190 191
191 public UUID FromFolderID; 192 public UUID FromFolderID;
192 193
193 194 // The following two are to hold the attachment data
195 // while an object is inworld
196 [XmlIgnore]
197 public byte AttachPoint = 0;
198
199 [XmlIgnore]
200 public Vector3 AttachOffset = Vector3.Zero;
201
202 [XmlIgnore]
194 public int STATUS_ROTATE_X; 203 public int STATUS_ROTATE_X;
195 204
196 205
@@ -285,6 +294,7 @@ namespace OpenSim.Region.Framework.Scenes
285 private Quaternion m_sitTargetOrientation = Quaternion.Identity; 294 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
286 private Vector3 m_sitTargetPosition; 295 private Vector3 m_sitTargetPosition;
287 private string m_sitAnimation = "SIT"; 296 private string m_sitAnimation = "SIT";
297 private bool m_occupied; // KF if any av is sitting on this prim
288 private string m_text = String.Empty; 298 private string m_text = String.Empty;
289 private string m_touchName = String.Empty; 299 private string m_touchName = String.Empty;
290 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); 300 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5);
@@ -374,7 +384,7 @@ namespace OpenSim.Region.Framework.Scenes
374 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, 384 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
375 Quaternion rotationOffset, Vector3 offsetPosition) 385 Quaternion rotationOffset, Vector3 offsetPosition)
376 { 386 {
377 m_name = "Primitive"; 387 m_name = "Object";
378 388
379 Rezzed = DateTime.UtcNow; 389 Rezzed = DateTime.UtcNow;
380 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed); 390 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
@@ -430,7 +440,7 @@ namespace OpenSim.Region.Framework.Scenes
430 private uint _ownerMask = (uint)PermissionMask.All; 440 private uint _ownerMask = (uint)PermissionMask.All;
431 private uint _groupMask = (uint)PermissionMask.None; 441 private uint _groupMask = (uint)PermissionMask.None;
432 private uint _everyoneMask = (uint)PermissionMask.None; 442 private uint _everyoneMask = (uint)PermissionMask.None;
433 private uint _nextOwnerMask = (uint)PermissionMask.All; 443 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
434 private PrimFlags _flags = PrimFlags.None; 444 private PrimFlags _flags = PrimFlags.None;
435 private DateTime m_expires; 445 private DateTime m_expires;
436 private DateTime m_rezzed; 446 private DateTime m_rezzed;
@@ -529,12 +539,16 @@ namespace OpenSim.Region.Framework.Scenes
529 } 539 }
530 540
531 /// <value> 541 /// <value>
532 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes 542 /// Get the inventory list
533 /// </value> 543 /// </value>
534 public TaskInventoryDictionary TaskInventory 544 public TaskInventoryDictionary TaskInventory
535 { 545 {
536 get { return m_inventory.Items; } 546 get {
537 set { m_inventory.Items = value; } 547 return m_inventory.Items;
548 }
549 set {
550 m_inventory.Items = value;
551 }
538 } 552 }
539 553
540 /// <summary> 554 /// <summary>
@@ -674,14 +688,12 @@ namespace OpenSim.Region.Framework.Scenes
674 set { m_LoopSoundSlavePrims = value; } 688 set { m_LoopSoundSlavePrims = value; }
675 } 689 }
676 690
677
678 public Byte[] TextureAnimation 691 public Byte[] TextureAnimation
679 { 692 {
680 get { return m_TextureAnimation; } 693 get { return m_TextureAnimation; }
681 set { m_TextureAnimation = value; } 694 set { m_TextureAnimation = value; }
682 } 695 }
683 696
684
685 public Byte[] ParticleSystem 697 public Byte[] ParticleSystem
686 { 698 {
687 get { return m_particleSystem; } 699 get { return m_particleSystem; }
@@ -718,9 +730,11 @@ namespace OpenSim.Region.Framework.Scenes
718 { 730 {
719 // If this is a linkset, we don't want the physics engine mucking up our group position here. 731 // If this is a linkset, we don't want the physics engine mucking up our group position here.
720 PhysicsActor actor = PhysActor; 732 PhysicsActor actor = PhysActor;
721 if (actor != null && _parentID == 0) 733 if (_parentID == 0)
722 { 734 {
723 m_groupPosition = actor.Position; 735 if (actor != null)
736 m_groupPosition = actor.Position;
737 return m_groupPosition;
724 } 738 }
725 739
726 if (IsAttachment) 740 if (IsAttachment)
@@ -730,12 +744,14 @@ namespace OpenSim.Region.Framework.Scenes
730 return sp.AbsolutePosition; 744 return sp.AbsolutePosition;
731 } 745 }
732 746
747 // use root prim's group position. Physics may have updated it
748 if (ParentGroup.RootPart != this)
749 m_groupPosition = ParentGroup.RootPart.GroupPosition;
733 return m_groupPosition; 750 return m_groupPosition;
734 } 751 }
735 set 752 set
736 { 753 {
737 m_groupPosition = value; 754 m_groupPosition = value;
738
739 PhysicsActor actor = PhysActor; 755 PhysicsActor actor = PhysActor;
740 if (actor != null) 756 if (actor != null)
741 { 757 {
@@ -755,25 +771,13 @@ namespace OpenSim.Region.Framework.Scenes
755 771
756 // Tell the physics engines that this prim changed. 772 // Tell the physics engines that this prim changed.
757 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 773 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
774
758 } 775 }
759 catch (Exception e) 776 catch (Exception e)
760 { 777 {
761 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 778 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
762 } 779 }
763 } 780 }
764
765 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
766 if (m_sitTargetAvatar != UUID.Zero)
767 {
768 if (m_parentGroup != null) // TODO can there be a SOP without a SOG?
769 {
770 ScenePresence avatar;
771 if (m_parentGroup.Scene.TryGetScenePresence(m_sitTargetAvatar, out avatar))
772 {
773 avatar.ParentPosition = GetWorldPosition();
774 }
775 }
776 }
777 } 781 }
778 } 782 }
779 783
@@ -782,7 +786,8 @@ namespace OpenSim.Region.Framework.Scenes
782 get { return m_offsetPosition; } 786 get { return m_offsetPosition; }
783 set 787 set
784 { 788 {
785 StoreUndoState(); 789 Vector3 oldpos = m_offsetPosition;
790 StoreUndoState(UndoType.STATE_PRIM_POSITION);
786 m_offsetPosition = value; 791 m_offsetPosition = value;
787 792
788 if (ParentGroup != null && !ParentGroup.IsDeleted) 793 if (ParentGroup != null && !ParentGroup.IsDeleted)
@@ -796,7 +801,22 @@ namespace OpenSim.Region.Framework.Scenes
796 // Tell the physics engines that this prim changed. 801 // Tell the physics engines that this prim changed.
797 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 802 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
798 } 803 }
804
805 if (!m_parentGroup.m_dupeInProgress)
806 {
807 List<ScenePresence> avs = ParentGroup.GetLinkedAvatars();
808 foreach (ScenePresence av in avs)
809 {
810 if (av.LinkedPrim == m_uuid)
811 {
812 Vector3 offset = (m_offsetPosition - oldpos);
813 av.OffsetPosition += offset;
814 av.SendAvatarDataToAllAgents();
815 }
816 }
817 }
799 } 818 }
819 TriggerScriptChangedEvent(Changed.POSITION);
800 } 820 }
801 } 821 }
802 822
@@ -838,7 +858,7 @@ namespace OpenSim.Region.Framework.Scenes
838 858
839 set 859 set
840 { 860 {
841 StoreUndoState(); 861 StoreUndoState(UndoType.STATE_PRIM_ROTATION);
842 m_rotationOffset = value; 862 m_rotationOffset = value;
843 863
844 PhysicsActor actor = PhysActor; 864 PhysicsActor actor = PhysActor;
@@ -922,7 +942,16 @@ namespace OpenSim.Region.Framework.Scenes
922 /// <summary></summary> 942 /// <summary></summary>
923 public Vector3 Acceleration 943 public Vector3 Acceleration
924 { 944 {
925 get { return m_acceleration; } 945 get
946 {
947 PhysicsActor actor = PhysActor;
948 if (actor != null)
949 {
950 m_acceleration = actor.Acceleration;
951 }
952 return m_acceleration;
953 }
954
926 set { m_acceleration = value; } 955 set { m_acceleration = value; }
927 } 956 }
928 957
@@ -1013,7 +1042,7 @@ namespace OpenSim.Region.Framework.Scenes
1013 get { return m_shape.Scale; } 1042 get { return m_shape.Scale; }
1014 set 1043 set
1015 { 1044 {
1016 StoreUndoState(); 1045 StoreUndoState(UndoType.STATE_PRIM_SCALE);
1017 if (m_shape != null) 1046 if (m_shape != null)
1018 { 1047 {
1019 m_shape.Scale = value; 1048 m_shape.Scale = value;
@@ -1079,11 +1108,10 @@ namespace OpenSim.Region.Framework.Scenes
1079 1108
1080 public Vector3 AbsolutePosition 1109 public Vector3 AbsolutePosition
1081 { 1110 {
1082 get { 1111 get
1083 if (IsAttachment) 1112 {
1084 return GroupPosition; 1113 return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset);
1085 1114 }
1086 return m_offsetPosition + m_groupPosition; }
1087 } 1115 }
1088 1116
1089 public SceneObjectGroup ParentGroup 1117 public SceneObjectGroup ParentGroup
@@ -1242,6 +1270,13 @@ namespace OpenSim.Region.Framework.Scenes
1242 _flags = value; 1270 _flags = value;
1243 } 1271 }
1244 } 1272 }
1273
1274 [XmlIgnore]
1275 public bool IsOccupied // KF If an av is sittingon this prim
1276 {
1277 get { return m_occupied; }
1278 set { m_occupied = value; }
1279 }
1245 1280
1246 1281
1247 public UUID SitTargetAvatar 1282 public UUID SitTargetAvatar
@@ -1317,14 +1352,6 @@ namespace OpenSim.Region.Framework.Scenes
1317 } 1352 }
1318 } 1353 }
1319 1354
1320 /// <summary>
1321 /// Clear all pending updates of parts to clients
1322 /// </summary>
1323 private void ClearUpdateSchedule()
1324 {
1325 m_updateFlag = 0;
1326 }
1327
1328 private void SendObjectPropertiesToClient(UUID AgentID) 1355 private void SendObjectPropertiesToClient(UUID AgentID)
1329 { 1356 {
1330 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1357 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
@@ -1575,14 +1602,22 @@ namespace OpenSim.Region.Framework.Scenes
1575 // or flexible 1602 // or flexible
1576 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) 1603 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible))
1577 { 1604 {
1578 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( 1605 try
1579 string.Format("{0}/{1}", Name, UUID), 1606 {
1580 Shape, 1607 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
1581 AbsolutePosition, 1608 string.Format("{0}/{1}", Name, UUID),
1582 Scale, 1609 Shape,
1583 RotationOffset, 1610 AbsolutePosition,
1584 RigidBody); 1611 Scale,
1585 1612 RotationOffset,
1613 RigidBody);
1614 PhysActor.SetMaterial(Material);
1615 }
1616 catch
1617 {
1618 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom.", m_uuid);
1619 PhysActor = null;
1620 }
1586 // Basic Physics returns null.. joy joy joy. 1621 // Basic Physics returns null.. joy joy joy.
1587 if (PhysActor != null) 1622 if (PhysActor != null)
1588 { 1623 {
@@ -1610,7 +1645,7 @@ namespace OpenSim.Region.Framework.Scenes
1610 { 1645 {
1611 m_redo.Clear(); 1646 m_redo.Clear();
1612 } 1647 }
1613 StoreUndoState(); 1648 StoreUndoState(UndoType.STATE_ALL);
1614 } 1649 }
1615 1650
1616 public byte ConvertScriptUintToByte(uint indata) 1651 public byte ConvertScriptUintToByte(uint indata)
@@ -1679,6 +1714,9 @@ namespace OpenSim.Region.Framework.Scenes
1679 1714
1680 // Move afterwards ResetIDs as it clears the localID 1715 // Move afterwards ResetIDs as it clears the localID
1681 dupe.LocalId = localID; 1716 dupe.LocalId = localID;
1717 if(dupe.PhysActor != null)
1718 dupe.PhysActor.LocalID = localID;
1719
1682 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. 1720 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1683 dupe._lastOwnerID = OwnerID; 1721 dupe._lastOwnerID = OwnerID;
1684 1722
@@ -1722,7 +1760,7 @@ namespace OpenSim.Region.Framework.Scenes
1722 PrimitiveBaseShape shape = PrimitiveBaseShape.Create(); 1760 PrimitiveBaseShape shape = PrimitiveBaseShape.Create();
1723 part.Shape = shape; 1761 part.Shape = shape;
1724 1762
1725 part.Name = "Primitive"; 1763 part.Name = "Object";
1726 part._ownerID = UUID.Random(); 1764 part._ownerID = UUID.Random();
1727 1765
1728 return part; 1766 return part;
@@ -2082,12 +2120,17 @@ namespace OpenSim.Region.Framework.Scenes
2082 public Vector3 GetWorldPosition() 2120 public Vector3 GetWorldPosition()
2083 { 2121 {
2084 Quaternion parentRot = ParentGroup.RootPart.RotationOffset; 2122 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
2085
2086 Vector3 axPos = OffsetPosition; 2123 Vector3 axPos = OffsetPosition;
2087
2088 axPos *= parentRot; 2124 axPos *= parentRot;
2089 Vector3 translationOffsetPosition = axPos; 2125 Vector3 translationOffsetPosition = axPos;
2090 return GroupPosition + translationOffsetPosition; 2126 if(_parentID == 0)
2127 {
2128 return GroupPosition;
2129 }
2130 else
2131 {
2132 return ParentGroup.AbsolutePosition + translationOffsetPosition; //KF: Fix child prim position
2133 }
2091 } 2134 }
2092 2135
2093 /// <summary> 2136 /// <summary>
@@ -2098,7 +2141,7 @@ namespace OpenSim.Region.Framework.Scenes
2098 { 2141 {
2099 Quaternion newRot; 2142 Quaternion newRot;
2100 2143
2101 if (this.LinkNum == 0) 2144 if (this.LinkNum < 2) //KF Single or root prim
2102 { 2145 {
2103 newRot = RotationOffset; 2146 newRot = RotationOffset;
2104 } 2147 }
@@ -2744,17 +2787,18 @@ namespace OpenSim.Region.Framework.Scenes
2744 //Trys to fetch sound id from prim's inventory. 2787 //Trys to fetch sound id from prim's inventory.
2745 //Prim's inventory doesn't support non script items yet 2788 //Prim's inventory doesn't support non script items yet
2746 2789
2747 lock (TaskInventory) 2790 TaskInventory.LockItemsForRead(true);
2791
2792 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2748 { 2793 {
2749 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 2794 if (item.Value.Name == sound)
2750 { 2795 {
2751 if (item.Value.Name == sound) 2796 soundID = item.Value.ItemID;
2752 { 2797 break;
2753 soundID = item.Value.ItemID;
2754 break;
2755 }
2756 } 2798 }
2757 } 2799 }
2800
2801 TaskInventory.LockItemsForRead(false);
2758 } 2802 }
2759 2803
2760 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp) 2804 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp)
@@ -2814,7 +2858,7 @@ namespace OpenSim.Region.Framework.Scenes
2814 /// <param name="scale"></param> 2858 /// <param name="scale"></param>
2815 public void Resize(Vector3 scale) 2859 public void Resize(Vector3 scale)
2816 { 2860 {
2817 StoreUndoState(); 2861 StoreUndoState(UndoType.STATE_PRIM_SCALE);
2818 m_shape.Scale = scale; 2862 m_shape.Scale = scale;
2819 2863
2820 ParentGroup.HasGroupChanged = true; 2864 ParentGroup.HasGroupChanged = true;
@@ -2823,38 +2867,7 @@ namespace OpenSim.Region.Framework.Scenes
2823 2867
2824 public void RotLookAt(Quaternion target, float strength, float damping) 2868 public void RotLookAt(Quaternion target, float strength, float damping)
2825 { 2869 {
2826 rotLookAt(target, strength, damping); 2870 m_parentGroup.rotLookAt(target, strength, damping); // This calls method in SceneObjectGroup.
2827 }
2828
2829 public void rotLookAt(Quaternion target, float strength, float damping)
2830 {
2831 if (IsAttachment)
2832 {
2833 /*
2834 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2835 if (avatar != null)
2836 {
2837 Rotate the Av?
2838 } */
2839 }
2840 else
2841 {
2842 APIDDamp = damping;
2843 APIDStrength = strength;
2844 APIDTarget = target;
2845 }
2846 }
2847
2848 public void startLookAt(Quaternion rot, float damp, float strength)
2849 {
2850 APIDDamp = damp;
2851 APIDStrength = strength;
2852 APIDTarget = rot;
2853 }
2854
2855 public void stopLookAt()
2856 {
2857 APIDTarget = Quaternion.Identity;
2858 } 2871 }
2859 2872
2860 /// <summary> 2873 /// <summary>
@@ -2866,7 +2879,10 @@ namespace OpenSim.Region.Framework.Scenes
2866 2879
2867 if (m_parentGroup != null) 2880 if (m_parentGroup != null)
2868 { 2881 {
2869 m_parentGroup.QueueForUpdateCheck(); 2882 if (!m_parentGroup.areUpdatesSuspended)
2883 {
2884 m_parentGroup.QueueForUpdateCheck();
2885 }
2870 } 2886 }
2871 2887
2872 int timeNow = Util.UnixTimeSinceEpoch(); 2888 int timeNow = Util.UnixTimeSinceEpoch();
@@ -3083,8 +3099,8 @@ namespace OpenSim.Region.Framework.Scenes
3083 { 3099 {
3084 const float ROTATION_TOLERANCE = 0.01f; 3100 const float ROTATION_TOLERANCE = 0.01f;
3085 const float VELOCITY_TOLERANCE = 0.001f; 3101 const float VELOCITY_TOLERANCE = 0.001f;
3086 const float POSITION_TOLERANCE = 0.05f; 3102 const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary
3087 const int TIME_MS_TOLERANCE = 3000; 3103 const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds.
3088 3104
3089 if (m_updateFlag == 1) 3105 if (m_updateFlag == 1)
3090 { 3106 {
@@ -3098,7 +3114,7 @@ namespace OpenSim.Region.Framework.Scenes
3098 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) 3114 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
3099 { 3115 {
3100 AddTerseUpdateToAllAvatars(); 3116 AddTerseUpdateToAllAvatars();
3101 ClearUpdateSchedule(); 3117
3102 3118
3103 // This causes the Scene to 'poll' physical objects every couple of frames 3119 // This causes the Scene to 'poll' physical objects every couple of frames
3104 // bad, so it's been replaced by an event driven method. 3120 // bad, so it's been replaced by an event driven method.
@@ -3116,16 +3132,18 @@ namespace OpenSim.Region.Framework.Scenes
3116 m_lastAngularVelocity = AngularVelocity; 3132 m_lastAngularVelocity = AngularVelocity;
3117 m_lastTerseSent = Environment.TickCount; 3133 m_lastTerseSent = Environment.TickCount;
3118 } 3134 }
3135 //Moved this outside of the if clause so updates don't get blocked.. *sigh*
3136 m_updateFlag = 0; //Why were we calling a function to do this? Inefficient! *screams*
3119 } 3137 }
3120 else 3138 else
3121 { 3139 {
3122 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes 3140 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes
3123 { 3141 {
3124 AddFullUpdateToAllAvatars(); 3142 AddFullUpdateToAllAvatars();
3125 ClearUpdateSchedule(); 3143 m_updateFlag = 0; //Same here
3126 } 3144 }
3127 } 3145 }
3128 ClearUpdateSchedule(); 3146 m_updateFlag = 0;
3129 } 3147 }
3130 3148
3131 /// <summary> 3149 /// <summary>
@@ -3153,17 +3171,16 @@ namespace OpenSim.Region.Framework.Scenes
3153 if (!UUID.TryParse(sound, out soundID)) 3171 if (!UUID.TryParse(sound, out soundID))
3154 { 3172 {
3155 // search sound file from inventory 3173 // search sound file from inventory
3156 lock (TaskInventory) 3174 TaskInventory.LockItemsForRead(true);
3175 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
3157 { 3176 {
3158 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3177 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
3159 { 3178 {
3160 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) 3179 soundID = item.Value.ItemID;
3161 { 3180 break;
3162 soundID = item.Value.ItemID;
3163 break;
3164 }
3165 } 3181 }
3166 } 3182 }
3183 TaskInventory.LockItemsForRead(false);
3167 } 3184 }
3168 3185
3169 if (soundID == UUID.Zero) 3186 if (soundID == UUID.Zero)
@@ -3593,7 +3610,7 @@ namespace OpenSim.Region.Framework.Scenes
3593 3610
3594 public void StopLookAt() 3611 public void StopLookAt()
3595 { 3612 {
3596 m_parentGroup.stopLookAt(); 3613 m_parentGroup.stopLookAt(); // This calls method in SceneObjectGroup.
3597 3614
3598 m_parentGroup.ScheduleGroupForTerseUpdate(); 3615 m_parentGroup.ScheduleGroupForTerseUpdate();
3599 } 3616 }
@@ -3620,10 +3637,9 @@ namespace OpenSim.Region.Framework.Scenes
3620 m_parentGroup.ScheduleGroupForTerseUpdate(); 3637 m_parentGroup.ScheduleGroupForTerseUpdate();
3621 //m_parentGroup.ScheduleGroupForFullUpdate(); 3638 //m_parentGroup.ScheduleGroupForFullUpdate();
3622 } 3639 }
3623 3640 public void StoreUndoState(UndoType type)
3624 public void StoreUndoState()
3625 { 3641 {
3626 if (!Undoing) 3642 if (!Undoing && (m_parentGroup == null || m_parentGroup.RootPart == null || !m_parentGroup.RootPart.Undoing))
3627 { 3643 {
3628 if (!IgnoreUndoUpdate) 3644 if (!IgnoreUndoUpdate)
3629 { 3645 {
@@ -3634,17 +3650,25 @@ namespace OpenSim.Region.Framework.Scenes
3634 if (m_undo.Count > 0) 3650 if (m_undo.Count > 0)
3635 { 3651 {
3636 UndoState last = m_undo.Peek(); 3652 UndoState last = m_undo.Peek();
3637 if (last != null) 3653
3638 {
3639 if (last.Compare(this))
3640 return;
3641 }
3642 } 3654 }
3643 3655
3644 if (m_parentGroup.GetSceneMaxUndo() > 0) 3656 if (m_parentGroup.GetSceneMaxUndo() > 0)
3645 { 3657 {
3646 UndoState nUndo = new UndoState(this); 3658 UndoState lastUndo = m_undo.Peek();
3647 3659
3660 UndoState nUndo = new UndoState(this, type);
3661
3662 if (lastUndo != null)
3663 {
3664 TimeSpan ts = DateTime.Now.Subtract(lastUndo.LastUpdated);
3665 if (ts.TotalMilliseconds < 500)
3666 {
3667 //Delete the last entry since it was less than 500 milliseconds ago
3668 nUndo.Merge(lastUndo);
3669 m_undo.Pop();
3670 }
3671 }
3648 m_undo.Push(nUndo); 3672 m_undo.Push(nUndo);
3649 } 3673 }
3650 3674
@@ -4121,11 +4145,13 @@ namespace OpenSim.Region.Framework.Scenes
4121 if (m_undo.Count > 0) 4145 if (m_undo.Count > 0)
4122 { 4146 {
4123 UndoState nUndo = null; 4147 UndoState nUndo = null;
4148 UndoState goback = m_undo.Pop();
4124 if (m_parentGroup.GetSceneMaxUndo() > 0) 4149 if (m_parentGroup.GetSceneMaxUndo() > 0)
4125 { 4150 {
4126 nUndo = new UndoState(this); 4151 nUndo = new UndoState(this, goback.Type);
4127 } 4152 }
4128 UndoState goback = m_undo.Pop(); 4153
4154
4129 if (goback != null) 4155 if (goback != null)
4130 { 4156 {
4131 goback.PlaybackState(this); 4157 goback.PlaybackState(this);
@@ -4140,13 +4166,13 @@ namespace OpenSim.Region.Framework.Scenes
4140 { 4166 {
4141 lock (m_redo) 4167 lock (m_redo)
4142 { 4168 {
4169 UndoState gofwd = m_redo.Pop();
4143 if (m_parentGroup.GetSceneMaxUndo() > 0) 4170 if (m_parentGroup.GetSceneMaxUndo() > 0)
4144 { 4171 {
4145 UndoState nUndo = new UndoState(this); 4172 UndoState nUndo = new UndoState(this, gofwd.Type);
4146 4173
4147 m_undo.Push(nUndo); 4174 m_undo.Push(nUndo);
4148 } 4175 }
4149 UndoState gofwd = m_redo.Pop();
4150 if (gofwd != null) 4176 if (gofwd != null)
4151 gofwd.PlayfwdState(this); 4177 gofwd.PlayfwdState(this);
4152 } 4178 }
@@ -4410,6 +4436,7 @@ namespace OpenSim.Region.Framework.Scenes
4410 Scale, 4436 Scale,
4411 RotationOffset, 4437 RotationOffset,
4412 UsePhysics); 4438 UsePhysics);
4439 PhysActor.SetMaterial(Material);
4413 4440
4414 pa = PhysActor; 4441 pa = PhysActor;
4415 if (pa != null) 4442 if (pa != null)
@@ -4595,8 +4622,9 @@ namespace OpenSim.Region.Framework.Scenes
4595 { 4622 {
4596 m_shape.TextureEntry = textureEntry; 4623 m_shape.TextureEntry = textureEntry;
4597 TriggerScriptChangedEvent(Changed.TEXTURE); 4624 TriggerScriptChangedEvent(Changed.TEXTURE);
4598 4625 m_updateFlag = 1;
4599 ParentGroup.HasGroupChanged = true; 4626 ParentGroup.HasGroupChanged = true;
4627
4600 //This is madness.. 4628 //This is madness..
4601 //ParentGroup.ScheduleGroupForFullUpdate(); 4629 //ParentGroup.ScheduleGroupForFullUpdate();
4602 //This is sparta 4630 //This is sparta
@@ -4829,5 +4857,17 @@ namespace OpenSim.Region.Framework.Scenes
4829 Color color = Color; 4857 Color color = Color;
4830 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); 4858 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4831 } 4859 }
4860
4861 public void ResetOwnerChangeFlag()
4862 {
4863 List<UUID> inv = Inventory.GetInventoryList();
4864
4865 foreach (UUID itemID in inv)
4866 {
4867 TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
4868 item.OwnerChanged = false;
4869 Inventory.UpdateInventoryItem(item, false, false);
4870 }
4871 }
4832 } 4872 }
4833} 4873}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 39ebaef..970003a 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -48,6 +48,8 @@ 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
52 private Dictionary<UUID, ArrayList> m_scriptErrors = new Dictionary<UUID, ArrayList>();
51 53
52 /// <value> 54 /// <value>
53 /// The part to which the inventory belongs. 55 /// The part to which the inventory belongs.
@@ -84,7 +86,9 @@ namespace OpenSim.Region.Framework.Scenes
84 /// </value> 86 /// </value>
85 protected internal TaskInventoryDictionary Items 87 protected internal TaskInventoryDictionary Items
86 { 88 {
87 get { return m_items; } 89 get {
90 return m_items;
91 }
88 set 92 set
89 { 93 {
90 m_items = value; 94 m_items = value;
@@ -120,39 +124,45 @@ namespace OpenSim.Region.Framework.Scenes
120 /// <param name="linkNum">Link number for the part</param> 124 /// <param name="linkNum">Link number for the part</param>
121 public void ResetInventoryIDs() 125 public void ResetInventoryIDs()
122 { 126 {
123 if (null == m_part || null == m_part.ParentGroup) 127 m_items.LockItemsForWrite(true);
124 return; 128
125 129 if (Items.Count == 0)
126 lock (m_items)
127 { 130 {
128 if (0 == m_items.Count) 131 m_items.LockItemsForWrite(false);
129 return; 132 return;
133 }
130 134
131 IList<TaskInventoryItem> items = GetInventoryItems(); 135 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
132 m_items.Clear(); 136 Items.Clear();
133 137
134 foreach (TaskInventoryItem item in items) 138 foreach (TaskInventoryItem item in items)
135 { 139 {
136 item.ResetIDs(m_part.UUID); 140 item.ResetIDs(m_part.UUID);
137 m_items.Add(item.ItemID, item); 141 Items.Add(item.ItemID, item);
138 }
139 } 142 }
143 m_items.LockItemsForWrite(false);
140 } 144 }
141 145
142 public void ResetObjectID() 146 public void ResetObjectID()
143 { 147 {
144 lock (Items) 148 m_items.LockItemsForWrite(true);
149
150 if (Items.Count == 0)
145 { 151 {
146 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); 152 m_items.LockItemsForWrite(false);
147 Items.Clear(); 153 return;
148
149 foreach (TaskInventoryItem item in items)
150 {
151 item.ParentPartID = m_part.UUID;
152 item.ParentID = m_part.UUID;
153 Items.Add(item.ItemID, item);
154 }
155 } 154 }
155
156 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
157 Items.Clear();
158
159 foreach (TaskInventoryItem item in items)
160 {
161 item.ParentPartID = m_part.UUID;
162 item.ParentID = m_part.UUID;
163 Items.Add(item.ItemID, item);
164 }
165 m_items.LockItemsForWrite(false);
156 } 166 }
157 167
158 /// <summary> 168 /// <summary>
@@ -161,12 +171,11 @@ namespace OpenSim.Region.Framework.Scenes
161 /// <param name="ownerId"></param> 171 /// <param name="ownerId"></param>
162 public void ChangeInventoryOwner(UUID ownerId) 172 public void ChangeInventoryOwner(UUID ownerId)
163 { 173 {
164 lock (Items) 174 m_items.LockItemsForWrite(true);
175 if (0 == Items.Count)
165 { 176 {
166 if (0 == Items.Count) 177 m_items.LockItemsForWrite(false);
167 { 178 return;
168 return;
169 }
170 } 179 }
171 180
172 HasInventoryChanged = true; 181 HasInventoryChanged = true;
@@ -180,6 +189,7 @@ namespace OpenSim.Region.Framework.Scenes
180 item.OwnerID = ownerId; 189 item.OwnerID = ownerId;
181 } 190 }
182 } 191 }
192 m_items.LockItemsForWrite(false);
183 } 193 }
184 194
185 /// <summary> 195 /// <summary>
@@ -188,12 +198,11 @@ namespace OpenSim.Region.Framework.Scenes
188 /// <param name="groupID"></param> 198 /// <param name="groupID"></param>
189 public void ChangeInventoryGroup(UUID groupID) 199 public void ChangeInventoryGroup(UUID groupID)
190 { 200 {
191 lock (Items) 201 m_items.LockItemsForWrite(true);
202 if (0 == Items.Count)
192 { 203 {
193 if (0 == Items.Count) 204 m_items.LockItemsForWrite(false);
194 { 205 return;
195 return;
196 }
197 } 206 }
198 207
199 // Don't let this set the HasGroupChanged flag for attachments 208 // Don't let this set the HasGroupChanged flag for attachments
@@ -205,12 +214,15 @@ namespace OpenSim.Region.Framework.Scenes
205 m_part.ParentGroup.HasGroupChanged = true; 214 m_part.ParentGroup.HasGroupChanged = true;
206 } 215 }
207 216
208 List<TaskInventoryItem> items = GetInventoryItems(); 217 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
209 foreach (TaskInventoryItem item in items) 218 foreach (TaskInventoryItem item in items)
210 { 219 {
211 if (groupID != item.GroupID) 220 if (groupID != item.GroupID)
221 {
212 item.GroupID = groupID; 222 item.GroupID = groupID;
223 }
213 } 224 }
225 m_items.LockItemsForWrite(false);
214 } 226 }
215 227
216 /// <summary> 228 /// <summary>
@@ -218,9 +230,14 @@ namespace OpenSim.Region.Framework.Scenes
218 /// </summary> 230 /// </summary>
219 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) 231 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
220 { 232 {
221 List<TaskInventoryItem> scripts = GetInventoryScripts(); 233 Items.LockItemsForRead(true);
222 foreach (TaskInventoryItem item in scripts) 234 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
223 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 235 Items.LockItemsForRead(false);
236 foreach (TaskInventoryItem item in items)
237 {
238 if ((int)InventoryType.LSL == item.InvType)
239 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
240 }
224 } 241 }
225 242
226 public ArrayList GetScriptErrors(UUID itemID) 243 public ArrayList GetScriptErrors(UUID itemID)
@@ -253,9 +270,18 @@ namespace OpenSim.Region.Framework.Scenes
253 /// </param> 270 /// </param>
254 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 271 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
255 { 272 {
256 List<TaskInventoryItem> scripts = GetInventoryScripts(); 273 Items.LockItemsForRead(true);
257 foreach (TaskInventoryItem item in scripts) 274 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
258 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); 275 Items.LockItemsForRead(false);
276
277 foreach (TaskInventoryItem item in items)
278 {
279 if ((int)InventoryType.LSL == item.InvType)
280 {
281 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
282 m_part.RemoveScriptEvents(item.ItemID);
283 }
284 }
259 } 285 }
260 286
261 /// <summary> 287 /// <summary>
@@ -271,7 +297,10 @@ namespace OpenSim.Region.Framework.Scenes
271 // item.Name, item.ItemID, Name, UUID); 297 // item.Name, item.ItemID, Name, UUID);
272 298
273 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) 299 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
300 {
301 StoreScriptError(item.ItemID, "no permission");
274 return; 302 return;
303 }
275 304
276 m_part.AddFlag(PrimFlags.Scripted); 305 m_part.AddFlag(PrimFlags.Scripted);
277 306
@@ -280,14 +309,13 @@ namespace OpenSim.Region.Framework.Scenes
280 if (stateSource == 2 && // Prim crossing 309 if (stateSource == 2 && // Prim crossing
281 m_part.ParentGroup.Scene.m_trustBinaries) 310 m_part.ParentGroup.Scene.m_trustBinaries)
282 { 311 {
283 lock (m_items) 312 m_items.LockItemsForWrite(true);
284 { 313 m_items[item.ItemID].PermsMask = 0;
285 m_items[item.ItemID].PermsMask = 0; 314 m_items[item.ItemID].PermsGranter = UUID.Zero;
286 m_items[item.ItemID].PermsGranter = UUID.Zero; 315 m_items.LockItemsForWrite(false);
287 }
288
289 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 316 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
290 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); 317 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
318 StoreScriptErrors(item.ItemID, null);
291 m_part.ParentGroup.AddActiveScriptCount(1); 319 m_part.ParentGroup.AddActiveScriptCount(1);
292 m_part.ScheduleFullUpdate(); 320 m_part.ScheduleFullUpdate();
293 return; 321 return;
@@ -296,6 +324,8 @@ namespace OpenSim.Region.Framework.Scenes
296 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 324 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
297 if (null == asset) 325 if (null == asset)
298 { 326 {
327 string msg = String.Format("asset ID {0} could not be found", item.AssetID);
328 StoreScriptError(item.ItemID, msg);
299 m_log.ErrorFormat( 329 m_log.ErrorFormat(
300 "[PRIM INVENTORY]: " + 330 "[PRIM INVENTORY]: " +
301 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", 331 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
@@ -307,15 +337,17 @@ namespace OpenSim.Region.Framework.Scenes
307 if (m_part.ParentGroup.m_savedScriptState != null) 337 if (m_part.ParentGroup.m_savedScriptState != null)
308 RestoreSavedScriptState(item.OldItemID, item.ItemID); 338 RestoreSavedScriptState(item.OldItemID, item.ItemID);
309 339
310 lock (m_items) 340 m_items.LockItemsForWrite(true);
311 { 341
312 m_items[item.ItemID].PermsMask = 0; 342 m_items[item.ItemID].PermsMask = 0;
313 m_items[item.ItemID].PermsGranter = UUID.Zero; 343 m_items[item.ItemID].PermsGranter = UUID.Zero;
314 } 344
345 m_items.LockItemsForWrite(false);
315 346
316 string script = Utils.BytesToString(asset.Data); 347 string script = Utils.BytesToString(asset.Data);
317 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 348 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
318 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); 349 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
350 StoreScriptErrors(item.ItemID, null);
319 m_part.ParentGroup.AddActiveScriptCount(1); 351 m_part.ParentGroup.AddActiveScriptCount(1);
320 m_part.ScheduleFullUpdate(); 352 m_part.ScheduleFullUpdate();
321 } 353 }
@@ -379,21 +411,145 @@ namespace OpenSim.Region.Framework.Scenes
379 411
380 /// <summary> 412 /// <summary>
381 /// Start a script which is in this prim's inventory. 413 /// Start a script which is in this prim's inventory.
414 /// Some processing may occur in the background, but this routine returns asap.
382 /// </summary> 415 /// </summary>
383 /// <param name="itemId"> 416 /// <param name="itemId">
384 /// A <see cref="UUID"/> 417 /// A <see cref="UUID"/>
385 /// </param> 418 /// </param>
386 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) 419 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
387 { 420 {
388 TaskInventoryItem item = GetInventoryItem(itemId); 421 lock (m_scriptErrors)
389 if (item != null) 422 {
390 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 423 // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
424 m_scriptErrors.Remove(itemId);
425 }
426 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
427 }
428
429 private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
430 {
431 m_items.LockItemsForRead(true);
432 if (m_items.ContainsKey(itemId))
433 {
434 if (m_items.ContainsKey(itemId))
435 {
436 m_items.LockItemsForRead(false);
437 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
438 }
439 else
440 {
441 m_items.LockItemsForRead(false);
442 string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
443 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
444 StoreScriptError(itemId, msg);
445 m_log.ErrorFormat(
446 "[PRIM INVENTORY]: " +
447 "Couldn't start script with ID {0} since it {1}", itemId, msg);
448 }
449 }
391 else 450 else
451 {
452 m_items.LockItemsForRead(false);
453 string msg = String.Format("couldn't be found for prim {0}, {1}", m_part.Name, m_part.UUID);
454 StoreScriptError(itemId, msg);
392 m_log.ErrorFormat( 455 m_log.ErrorFormat(
393 "[PRIM INVENTORY]: " + 456 "[PRIM INVENTORY]: " +
394 "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 457 "Couldn't start script with ID {0} since it {1}", itemId, msg);
395 itemId, m_part.Name, m_part.UUID, 458 }
396 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 459
460 }
461
462 /// <summary>
463 /// Start a script which is in this prim's inventory and return any compilation error messages.
464 /// </summary>
465 /// <param name="itemId">
466 /// A <see cref="UUID"/>
467 /// </param>
468 public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
469 {
470 ArrayList errors;
471
472 // Indicate to CreateScriptInstanceInternal() we want it to
473 // post any compilation/loading error messages
474 lock (m_scriptErrors)
475 {
476 m_scriptErrors[itemId] = null;
477 }
478
479 // Perform compilation/loading
480 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
481
482 // Wait for and retrieve any errors
483 lock (m_scriptErrors)
484 {
485 while ((errors = m_scriptErrors[itemId]) == null)
486 {
487 if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
488 {
489 m_log.ErrorFormat(
490 "[PRIM INVENTORY]: " +
491 "timedout waiting for script {0} errors", itemId);
492 errors = m_scriptErrors[itemId];
493 if (errors == null)
494 {
495 errors = new ArrayList(1);
496 errors.Add("timedout waiting for errors");
497 }
498 break;
499 }
500 }
501 m_scriptErrors.Remove(itemId);
502 }
503 return errors;
504 }
505
506 // Signal to CreateScriptInstanceEr() that compilation/loading is complete
507 private void StoreScriptErrors(UUID itemId, ArrayList errors)
508 {
509 lock (m_scriptErrors)
510 {
511 // If compilation/loading initiated via CreateScriptInstance(),
512 // it does not want the errors, so just get out
513 if (!m_scriptErrors.ContainsKey(itemId))
514 {
515 return;
516 }
517
518 // Initiated via CreateScriptInstanceEr(), if we know what the
519 // errors are, save them and wake CreateScriptInstanceEr().
520 if (errors != null)
521 {
522 m_scriptErrors[itemId] = errors;
523 System.Threading.Monitor.PulseAll(m_scriptErrors);
524 return;
525 }
526 }
527
528 // Initiated via CreateScriptInstanceEr() but we don't know what
529 // the errors are yet, so retrieve them from the script engine.
530 // This may involve some waiting internal to GetScriptErrors().
531 errors = GetScriptErrors(itemId);
532
533 // Get a default non-null value to indicate success.
534 if (errors == null)
535 {
536 errors = new ArrayList();
537 }
538
539 // Post to CreateScriptInstanceEr() and wake it up
540 lock (m_scriptErrors)
541 {
542 m_scriptErrors[itemId] = errors;
543 System.Threading.Monitor.PulseAll(m_scriptErrors);
544 }
545 }
546
547 // Like StoreScriptErrors(), but just posts a single string message
548 private void StoreScriptError(UUID itemId, string message)
549 {
550 ArrayList errors = new ArrayList(1);
551 errors.Add(message);
552 StoreScriptErrors(itemId, errors);
397 } 553 }
398 554
399 /// <summary> 555 /// <summary>
@@ -406,15 +562,7 @@ namespace OpenSim.Region.Framework.Scenes
406 /// </param> 562 /// </param>
407 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) 563 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
408 { 564 {
409 bool scriptPresent = false; 565 if (m_items.ContainsKey(itemId))
410
411 lock (m_items)
412 {
413 if (m_items.ContainsKey(itemId))
414 scriptPresent = true;
415 }
416
417 if (scriptPresent)
418 { 566 {
419 if (!sceneObjectBeingDeleted) 567 if (!sceneObjectBeingDeleted)
420 m_part.RemoveScriptEvents(itemId); 568 m_part.RemoveScriptEvents(itemId);
@@ -439,14 +587,16 @@ namespace OpenSim.Region.Framework.Scenes
439 /// <returns></returns> 587 /// <returns></returns>
440 private bool InventoryContainsName(string name) 588 private bool InventoryContainsName(string name)
441 { 589 {
442 lock (m_items) 590 m_items.LockItemsForRead(true);
591 foreach (TaskInventoryItem item in m_items.Values)
443 { 592 {
444 foreach (TaskInventoryItem item in m_items.Values) 593 if (item.Name == name)
445 { 594 {
446 if (item.Name == name) 595 m_items.LockItemsForRead(false);
447 return true; 596 return true;
448 } 597 }
449 } 598 }
599 m_items.LockItemsForRead(false);
450 return false; 600 return false;
451 } 601 }
452 602
@@ -488,8 +638,9 @@ namespace OpenSim.Region.Framework.Scenes
488 /// <param name="item"></param> 638 /// <param name="item"></param>
489 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) 639 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
490 { 640 {
491 List<TaskInventoryItem> il = GetInventoryItems(); 641 m_items.LockItemsForRead(true);
492 642 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
643 m_items.LockItemsForRead(false);
493 foreach (TaskInventoryItem i in il) 644 foreach (TaskInventoryItem i in il)
494 { 645 {
495 if (i.Name == item.Name) 646 if (i.Name == item.Name)
@@ -527,14 +678,14 @@ namespace OpenSim.Region.Framework.Scenes
527 item.Name = name; 678 item.Name = name;
528 item.GroupID = m_part.GroupID; 679 item.GroupID = m_part.GroupID;
529 680
530 lock (m_items) 681 m_items.LockItemsForWrite(true);
531 m_items.Add(item.ItemID, item); 682 m_items.Add(item.ItemID, item);
532 683 m_items.LockItemsForWrite(false);
533 if (allowedDrop) 684 if (allowedDrop)
534 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); 685 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
535 else 686 else
536 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 687 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
537 688
538 m_inventorySerial++; 689 m_inventorySerial++;
539 //m_inventorySerial += 2; 690 //m_inventorySerial += 2;
540 HasInventoryChanged = true; 691 HasInventoryChanged = true;
@@ -550,15 +701,15 @@ namespace OpenSim.Region.Framework.Scenes
550 /// <param name="items"></param> 701 /// <param name="items"></param>
551 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) 702 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
552 { 703 {
553 lock (m_items) 704 m_items.LockItemsForWrite(true);
705 foreach (TaskInventoryItem item in items)
554 { 706 {
555 foreach (TaskInventoryItem item in items) 707 m_items.Add(item.ItemID, item);
556 { 708// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
557 m_items.Add(item.ItemID, item);
558// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
559 }
560 m_inventorySerial++;
561 } 709 }
710 m_items.LockItemsForWrite(false);
711
712 m_inventorySerial++;
562 } 713 }
563 714
564 /// <summary> 715 /// <summary>
@@ -569,10 +720,9 @@ namespace OpenSim.Region.Framework.Scenes
569 public TaskInventoryItem GetInventoryItem(UUID itemId) 720 public TaskInventoryItem GetInventoryItem(UUID itemId)
570 { 721 {
571 TaskInventoryItem item; 722 TaskInventoryItem item;
572 723 m_items.LockItemsForRead(true);
573 lock (m_items) 724 m_items.TryGetValue(itemId, out item);
574 m_items.TryGetValue(itemId, out item); 725 m_items.LockItemsForRead(false);
575
576 return item; 726 return item;
577 } 727 }
578 728
@@ -588,15 +738,16 @@ namespace OpenSim.Region.Framework.Scenes
588 { 738 {
589 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(); 739 IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
590 740
591 lock (m_items) 741 m_items.LockItemsForRead(true);
742
743 foreach (TaskInventoryItem item in m_items.Values)
592 { 744 {
593 foreach (TaskInventoryItem item in m_items.Values) 745 if (item.Name == name)
594 { 746 items.Add(item);
595 if (item.Name == name)
596 items.Add(item);
597 }
598 } 747 }
599 748
749 m_items.LockItemsForRead(false);
750
600 return items; 751 return items;
601 } 752 }
602 753
@@ -679,9 +830,9 @@ namespace OpenSim.Region.Framework.Scenes
679 830
680 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) 831 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
681 { 832 {
682 TaskInventoryItem it = GetInventoryItem(item.ItemID); 833 m_items.LockItemsForWrite(true);
683 if (it != null)
684 834
835 if (m_items.ContainsKey(item.ItemID))
685 { 836 {
686 item.ParentID = m_part.UUID; 837 item.ParentID = m_part.UUID;
687 item.ParentPartID = m_part.UUID; 838 item.ParentPartID = m_part.UUID;
@@ -693,14 +844,10 @@ namespace OpenSim.Region.Framework.Scenes
693 item.GroupID = m_part.GroupID; 844 item.GroupID = m_part.GroupID;
694 845
695 if (item.AssetID == UUID.Zero) 846 if (item.AssetID == UUID.Zero)
696 item.AssetID = it.AssetID; 847 item.AssetID = m_items[item.ItemID].AssetID;
697
698 lock (m_items)
699 {
700 m_items[item.ItemID] = item;
701 m_inventorySerial++;
702 }
703 848
849 m_items[item.ItemID] = item;
850 m_inventorySerial++;
704 if (fireScriptEvents) 851 if (fireScriptEvents)
705 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 852 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
706 if (considerChanged) 853 if (considerChanged)
@@ -708,6 +855,7 @@ namespace OpenSim.Region.Framework.Scenes
708 HasInventoryChanged = true; 855 HasInventoryChanged = true;
709 m_part.ParentGroup.HasGroupChanged = true; 856 m_part.ParentGroup.HasGroupChanged = true;
710 } 857 }
858 m_items.LockItemsForWrite(false);
711 return true; 859 return true;
712 } 860 }
713 else 861 else
@@ -718,8 +866,9 @@ namespace OpenSim.Region.Framework.Scenes
718 item.ItemID, m_part.Name, m_part.UUID, 866 item.ItemID, m_part.Name, m_part.UUID,
719 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 867 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
720 } 868 }
721 return false; 869 m_items.LockItemsForWrite(false);
722 870
871 return false;
723 } 872 }
724 873
725 /// <summary> 874 /// <summary>
@@ -730,107 +879,68 @@ namespace OpenSim.Region.Framework.Scenes
730 /// in this prim's inventory.</returns> 879 /// in this prim's inventory.</returns>
731 public int RemoveInventoryItem(UUID itemID) 880 public int RemoveInventoryItem(UUID itemID)
732 { 881 {
733 TaskInventoryItem item = GetInventoryItem(itemID); 882 m_items.LockItemsForRead(true);
734 if (item != null) 883
884 if (m_items.ContainsKey(itemID))
735 { 885 {
736 int type = m_items[itemID].InvType; 886 int type = m_items[itemID].InvType;
887 m_items.LockItemsForRead(false);
737 if (type == 10) // Script 888 if (type == 10) // Script
738 { 889 {
739 m_part.RemoveScriptEvents(itemID);
740 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 890 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
741 } 891 }
892 m_items.LockItemsForWrite(true);
742 m_items.Remove(itemID); 893 m_items.Remove(itemID);
894 m_items.LockItemsForWrite(false);
743 m_inventorySerial++; 895 m_inventorySerial++;
744 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 896 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
745 897
746 HasInventoryChanged = true; 898 HasInventoryChanged = true;
747 m_part.ParentGroup.HasGroupChanged = true; 899 m_part.ParentGroup.HasGroupChanged = true;
748 900
749 if (!ContainsScripts()) 901 int scriptcount = 0;
902 m_items.LockItemsForRead(true);
903 foreach (TaskInventoryItem item in m_items.Values)
904 {
905 if (item.Type == 10)
906 {
907 scriptcount++;
908 }
909 }
910 m_items.LockItemsForRead(false);
911
912
913 if (scriptcount <= 0)
914 {
750 m_part.RemFlag(PrimFlags.Scripted); 915 m_part.RemFlag(PrimFlags.Scripted);
916 }
751 917
752 m_part.ScheduleFullUpdate(); 918 m_part.ScheduleFullUpdate();
753 919
754 return type; 920 return type;
755
756 } 921 }
757 else 922 else
758 { 923 {
924 m_items.LockItemsForRead(false);
759 m_log.ErrorFormat( 925 m_log.ErrorFormat(
760 "[PRIM INVENTORY]: " + 926 "[PRIM INVENTORY]: " +
761 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", 927 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
762 itemID, m_part.Name, m_part.UUID, 928 itemID, m_part.Name, m_part.UUID);
763 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
764 } 929 }
765 930
766 return -1; 931 return -1;
767 } 932 }
768 933
769 private bool CreateInventoryFile() 934 private bool CreateInventoryFileName()
770 { 935 {
771 if (m_inventoryFileName == String.Empty || 936 if (m_inventoryFileName == String.Empty ||
772 m_inventoryFileNameSerial < m_inventorySerial) 937 m_inventoryFileNameSerial < m_inventorySerial)
773 { 938 {
774 // Something changed, we need to create a new file
775 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; 939 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
776 m_inventoryFileNameSerial = m_inventorySerial; 940 m_inventoryFileNameSerial = m_inventorySerial;
777
778 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
779
780 lock (m_items)
781 {
782 foreach (TaskInventoryItem item in m_items.Values)
783 {
784 UUID ownerID = item.OwnerID;
785 uint everyoneMask = 0;
786 uint baseMask = item.BasePermissions;
787 uint ownerMask = item.CurrentPermissions;
788 uint groupMask = item.GroupPermissions;
789
790 invString.AddItemStart();
791 invString.AddNameValueLine("item_id", item.ItemID.ToString());
792 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
793
794 invString.AddPermissionsStart();
795
796 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
797 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
798 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
799 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
800 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
801
802 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
803 invString.AddNameValueLine("owner_id", ownerID.ToString());
804
805 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
806
807 invString.AddNameValueLine("group_id", item.GroupID.ToString());
808 invString.AddSectionEnd();
809
810 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
811 invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
812 invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
813 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
814
815 invString.AddSaleStart();
816 invString.AddNameValueLine("sale_type", "not");
817 invString.AddNameValueLine("sale_price", "0");
818 invString.AddSectionEnd();
819
820 invString.AddNameValueLine("name", item.Name + "|");
821 invString.AddNameValueLine("desc", item.Description + "|");
822
823 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
824 invString.AddSectionEnd();
825 }
826 }
827
828 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
829
830 return true; 941 return true;
831 } 942 }
832 943
833 // No need to recreate, the existing file is fine
834 return false; 944 return false;
835 } 945 }
836 946
@@ -840,26 +950,94 @@ namespace OpenSim.Region.Framework.Scenes
840 /// <param name="xferManager"></param> 950 /// <param name="xferManager"></param>
841 public void RequestInventoryFile(IClientAPI client, IXfer xferManager) 951 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
842 { 952 {
843 bool changed = CreateInventoryFile(); 953 bool changed = CreateInventoryFileName();
954
955 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
956
957 Items.LockItemsForRead(true);
844 958
845 if (m_inventorySerial == 0) // No inventory 959 if (m_inventorySerial == 0) // No inventory
846 { 960 {
847 client.SendTaskInventory(m_part.UUID, 0, new byte[0]); 961 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
962 Items.LockItemsForRead(false);
848 return; 963 return;
849 } 964 }
850 965
851 // In principle, we should only do the rest if the inventory changed; 966 if (!changed)
852 // by sending m_inventorySerial to the client, it ought to know 967 {
853 // that nothing changed and that it doesn't need to request the file. 968 if (m_inventoryFileData.Length > 2)
854 // Unfortunately, it doesn't look like the client optimizes this; 969 {
855 // the client seems to always come back and request the Xfer, 970 xferManager.AddNewFile(m_inventoryFileName,
856 // no matter what value m_inventorySerial has. 971 m_inventoryFileData);
972 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
973 Util.StringToBytes256(m_inventoryFileName));
974
975 Items.LockItemsForRead(false);
976 return;
977 }
978 }
979
980 bool includeAssets = false;
981 if (m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId))
982 includeAssets = true;
983
984 foreach (TaskInventoryItem item in m_items.Values)
985 {
986 UUID ownerID = item.OwnerID;
987 uint everyoneMask = 0;
988 uint baseMask = item.BasePermissions;
989 uint ownerMask = item.CurrentPermissions;
990 uint groupMask = item.GroupPermissions;
991
992 invString.AddItemStart();
993 invString.AddNameValueLine("item_id", item.ItemID.ToString());
994 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
995
996 invString.AddPermissionsStart();
997
998 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
999 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
1000 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
1001 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
1002 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
1003
1004 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
1005 invString.AddNameValueLine("owner_id", ownerID.ToString());
1006
1007 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
1008
1009 invString.AddNameValueLine("group_id", item.GroupID.ToString());
1010 invString.AddSectionEnd();
1011
1012 if (includeAssets)
1013 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
1014 else
1015 invString.AddNameValueLine("asset_id", UUID.Zero.ToString());
1016 invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
1017 invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
1018 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
1019
1020 invString.AddSaleStart();
1021 invString.AddNameValueLine("sale_type", "not");
1022 invString.AddNameValueLine("sale_price", "0");
1023 invString.AddSectionEnd();
1024
1025 invString.AddNameValueLine("name", item.Name + "|");
1026 invString.AddNameValueLine("desc", item.Description + "|");
1027
1028 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
1029 invString.AddSectionEnd();
1030 }
1031
1032 Items.LockItemsForRead(false);
1033
1034 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
857 1035
858 if (m_inventoryFileData.Length > 2) 1036 if (m_inventoryFileData.Length > 2)
859 // Add the file for Xfer 1037 {
860 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); 1038 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
1039 }
861 1040
862 // Tell the client we're ready to Xfer the file
863 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, 1041 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
864 Util.StringToBytes256(m_inventoryFileName)); 1042 Util.StringToBytes256(m_inventoryFileName));
865 } 1043 }
@@ -872,10 +1050,11 @@ namespace OpenSim.Region.Framework.Scenes
872 { 1050 {
873 if (HasInventoryChanged) 1051 if (HasInventoryChanged)
874 { 1052 {
875 HasInventoryChanged = false; 1053 Items.LockItemsForRead(true);
876 List<TaskInventoryItem> items = GetInventoryItems(); 1054 datastore.StorePrimInventory(m_part.UUID, Items.Values);
877 datastore.StorePrimInventory(m_part.UUID, items); 1055 Items.LockItemsForRead(false);
878 1056
1057 HasInventoryChanged = false;
879 } 1058 }
880 } 1059 }
881 1060
@@ -942,89 +1121,77 @@ namespace OpenSim.Region.Framework.Scenes
942 { 1121 {
943 uint mask=0x7fffffff; 1122 uint mask=0x7fffffff;
944 1123
945 lock (m_items) 1124 foreach (TaskInventoryItem item in m_items.Values)
946 { 1125 {
947 foreach (TaskInventoryItem item in m_items.Values) 1126 if (item.InvType != (int)InventoryType.Object)
948 { 1127 {
949 if (item.InvType != (int)InventoryType.Object) 1128 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
950 { 1129 mask &= ~((uint)PermissionMask.Copy >> 13);
951 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) 1130 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
952 mask &= ~((uint)PermissionMask.Copy >> 13); 1131 mask &= ~((uint)PermissionMask.Transfer >> 13);
953 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) 1132 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
954 mask &= ~((uint)PermissionMask.Transfer >> 13); 1133 mask &= ~((uint)PermissionMask.Modify >> 13);
955 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1134 }
956 mask &= ~((uint)PermissionMask.Modify >> 13); 1135 else
957 } 1136 {
958 else 1137 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
959 { 1138 mask &= ~((uint)PermissionMask.Copy >> 13);
960 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1139 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
961 mask &= ~((uint)PermissionMask.Copy >> 13); 1140 mask &= ~((uint)PermissionMask.Transfer >> 13);
962 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1141 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
963 mask &= ~((uint)PermissionMask.Transfer >> 13); 1142 mask &= ~((uint)PermissionMask.Modify >> 13);
964 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
965 mask &= ~((uint)PermissionMask.Modify >> 13);
966 }
967
968 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
969 mask &= ~(uint)PermissionMask.Copy;
970 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
971 mask &= ~(uint)PermissionMask.Transfer;
972 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
973 mask &= ~(uint)PermissionMask.Modify;
974 } 1143 }
1144
1145 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1146 mask &= ~(uint)PermissionMask.Copy;
1147 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1148 mask &= ~(uint)PermissionMask.Transfer;
1149 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1150 mask &= ~(uint)PermissionMask.Modify;
975 } 1151 }
976
977 return mask; 1152 return mask;
978 } 1153 }
979 1154
980 public void ApplyNextOwnerPermissions() 1155 public void ApplyNextOwnerPermissions()
981 { 1156 {
982 lock (m_items) 1157 foreach (TaskInventoryItem item in m_items.Values)
983 { 1158 {
984 foreach (TaskInventoryItem item in m_items.Values) 1159 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
985 { 1160 {
986 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1161 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
987 { 1162 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
988 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1163 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
989 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1164 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
990 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1165 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
991 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; 1166 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
992 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
993 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
994 }
995 item.CurrentPermissions &= item.NextPermissions;
996 item.BasePermissions &= item.NextPermissions;
997 item.EveryonePermissions &= item.NextPermissions;
998 item.OwnerChanged = true;
999 } 1167 }
1168 item.OwnerChanged = true;
1169 item.CurrentPermissions &= item.NextPermissions;
1170 item.BasePermissions &= item.NextPermissions;
1171 item.EveryonePermissions &= item.NextPermissions;
1000 } 1172 }
1001 } 1173 }
1002 1174
1003 public void ApplyGodPermissions(uint perms) 1175 public void ApplyGodPermissions(uint perms)
1004 { 1176 {
1005 lock (m_items) 1177 foreach (TaskInventoryItem item in m_items.Values)
1006 { 1178 {
1007 foreach (TaskInventoryItem item in m_items.Values) 1179 item.CurrentPermissions = perms;
1008 { 1180 item.BasePermissions = perms;
1009 item.CurrentPermissions = perms;
1010 item.BasePermissions = perms;
1011 }
1012 } 1181 }
1182 m_inventorySerial++;
1183 HasInventoryChanged = true;
1013 } 1184 }
1014 1185
1015 public bool ContainsScripts() 1186 public bool ContainsScripts()
1016 { 1187 {
1017 lock (m_items) 1188 foreach (TaskInventoryItem item in m_items.Values)
1018 { 1189 {
1019 foreach (TaskInventoryItem item in m_items.Values) 1190 if (item.InvType == (int)InventoryType.LSL)
1020 { 1191 {
1021 if (item.InvType == (int)InventoryType.LSL) 1192 return true;
1022 {
1023 return true;
1024 }
1025 } 1193 }
1026 } 1194 }
1027
1028 return false; 1195 return false;
1029 } 1196 }
1030 1197
@@ -1032,11 +1199,8 @@ namespace OpenSim.Region.Framework.Scenes
1032 { 1199 {
1033 List<UUID> ret = new List<UUID>(); 1200 List<UUID> ret = new List<UUID>();
1034 1201
1035 lock (m_items) 1202 foreach (TaskInventoryItem item in m_items.Values)
1036 { 1203 ret.Add(item.ItemID);
1037 foreach (TaskInventoryItem item in m_items.Values)
1038 ret.Add(item.ItemID);
1039 }
1040 1204
1041 return ret; 1205 return ret;
1042 } 1206 }
@@ -1067,31 +1231,46 @@ namespace OpenSim.Region.Framework.Scenes
1067 1231
1068 public Dictionary<UUID, string> GetScriptStates() 1232 public Dictionary<UUID, string> GetScriptStates()
1069 { 1233 {
1234 return GetScriptStates(false);
1235 }
1236
1237 public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
1238 {
1070 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); 1239 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1071 1240
1072 Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); 1241 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1073 if (engines == null) // No engine at all 1242 if (engines == null) // No engine at all
1074 return ret; 1243 return ret;
1075 1244
1076 List<TaskInventoryItem> scripts = GetInventoryScripts(); 1245 Items.LockItemsForRead(true);
1077 1246 foreach (TaskInventoryItem item in m_items.Values)
1078 foreach (TaskInventoryItem item in scripts)
1079 { 1247 {
1080 foreach (IScriptModule e in engines) 1248 if (item.InvType == (int)InventoryType.LSL)
1081 { 1249 {
1082 if (e != null) 1250 foreach (IScriptModule e in engines)
1083 { 1251 {
1084 string n = e.GetXMLState(item.ItemID); 1252 if (e != null)
1085 if (n != String.Empty)
1086 { 1253 {
1087 if (!ret.ContainsKey(item.ItemID)) 1254 string n = e.GetXMLState(item.ItemID);
1088 ret[item.ItemID] = n; 1255 if (n != String.Empty)
1089 break; 1256 {
1257 if (oldIDs)
1258 {
1259 if (!ret.ContainsKey(item.OldItemID))
1260 ret[item.OldItemID] = n;
1261 }
1262 else
1263 {
1264 if (!ret.ContainsKey(item.ItemID))
1265 ret[item.ItemID] = n;
1266 }
1267 break;
1268 }
1090 } 1269 }
1091 } 1270 }
1092 } 1271 }
1093 } 1272 }
1094 1273 Items.LockItemsForRead(false);
1095 return ret; 1274 return ret;
1096 } 1275 }
1097 1276
@@ -1101,21 +1280,27 @@ namespace OpenSim.Region.Framework.Scenes
1101 if (engines == null) 1280 if (engines == null)
1102 return; 1281 return;
1103 1282
1104 List<TaskInventoryItem> scripts = GetInventoryScripts();
1105 1283
1106 foreach (TaskInventoryItem item in scripts) 1284 Items.LockItemsForRead(true);
1285
1286 foreach (TaskInventoryItem item in m_items.Values)
1107 { 1287 {
1108 foreach (IScriptModule engine in engines) 1288 if (item.InvType == (int)InventoryType.LSL)
1109 { 1289 {
1110 if (engine != null) 1290 foreach (IScriptModule engine in engines)
1111 { 1291 {
1112 if (item.OwnerChanged) 1292 if (engine != null)
1113 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); 1293 {
1114 item.OwnerChanged = false; 1294 if (item.OwnerChanged)
1115 engine.ResumeScript(item.ItemID); 1295 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1296 item.OwnerChanged = false;
1297 engine.ResumeScript(item.ItemID);
1298 }
1116 } 1299 }
1117 } 1300 }
1118 } 1301 }
1302
1303 Items.LockItemsForRead(false);
1119 } 1304 }
1120 } 1305 }
1121} 1306}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 3a40196..b8ad3ca 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Xml;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
31using System.Timers; 32using System.Timers;
@@ -72,7 +73,7 @@ namespace OpenSim.Region.Framework.Scenes
72// { 73// {
73// m_log.Debug("[ScenePresence] Destructor called"); 74// m_log.Debug("[ScenePresence] Destructor called");
74// } 75// }
75 76
76 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
77 78
78// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); 79// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
@@ -87,7 +88,9 @@ namespace OpenSim.Region.Framework.Scenes
87 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis 88 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
88 /// issue #1716 89 /// issue #1716
89 /// </summary> 90 /// </summary>
90 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f); 91// private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f);
92 // Value revised by KF 091121 by comparison with SL.
93 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f);
91 94
92 public UUID currentParcelUUID = UUID.Zero; 95 public UUID currentParcelUUID = UUID.Zero;
93 96
@@ -121,8 +124,11 @@ namespace OpenSim.Region.Framework.Scenes
121 public Vector3 lastKnownAllowedPosition; 124 public Vector3 lastKnownAllowedPosition;
122 public bool sentMessageAboutRestrictedParcelFlyingDown; 125 public bool sentMessageAboutRestrictedParcelFlyingDown;
123 public Vector4 CollisionPlane = Vector4.UnitW; 126 public Vector4 CollisionPlane = Vector4.UnitW;
124 127
128 private Vector3 m_avInitialPos; // used to calculate unscripted sit rotation
129 private Vector3 m_avUnscriptedSitPos; // for non-scripted prims
125 private Vector3 m_lastPosition; 130 private Vector3 m_lastPosition;
131 private Vector3 m_lastWorldPosition;
126 private Quaternion m_lastRotation; 132 private Quaternion m_lastRotation;
127 private Vector3 m_lastVelocity; 133 private Vector3 m_lastVelocity;
128 //private int m_lastTerseSent; 134 //private int m_lastTerseSent;
@@ -153,9 +159,10 @@ namespace OpenSim.Region.Framework.Scenes
153 private int m_perfMonMS; 159 private int m_perfMonMS;
154 160
155 private bool m_setAlwaysRun; 161 private bool m_setAlwaysRun;
156
157 private bool m_forceFly; 162 private bool m_forceFly;
158 private bool m_flyDisabled; 163 private bool m_flyDisabled;
164 private bool m_flyingOld; // add for fly velocity control
165 public bool m_wasFlying; // add for fly velocity control
159 166
160 private float m_speedModifier = 1.0f; 167 private float m_speedModifier = 1.0f;
161 168
@@ -174,7 +181,8 @@ namespace OpenSim.Region.Framework.Scenes
174 protected RegionInfo m_regionInfo; 181 protected RegionInfo m_regionInfo;
175 protected ulong crossingFromRegion; 182 protected ulong crossingFromRegion;
176 183
177 private readonly Vector3[] Dir_Vectors = new Vector3[9]; 184 private readonly Vector3[] Dir_Vectors = new Vector3[11];
185 private bool m_isNudging = false;
178 186
179 // Position of agent's camera in world (region cordinates) 187 // Position of agent's camera in world (region cordinates)
180 protected Vector3 m_CameraCenter; 188 protected Vector3 m_CameraCenter;
@@ -199,17 +207,25 @@ namespace OpenSim.Region.Framework.Scenes
199 private bool m_autopilotMoving; 207 private bool m_autopilotMoving;
200 private Vector3 m_autoPilotTarget; 208 private Vector3 m_autoPilotTarget;
201 private bool m_sitAtAutoTarget; 209 private bool m_sitAtAutoTarget;
210 private Vector3 m_initialSitTarget = Vector3.Zero; //KF: First estimate of where to sit
202 211
203 private string m_nextSitAnimation = String.Empty; 212 private string m_nextSitAnimation = String.Empty;
204 213
205 //PauPaw:Proper PID Controler for autopilot************ 214 //PauPaw:Proper PID Controler for autopilot************
206 private bool m_moveToPositionInProgress; 215 private bool m_moveToPositionInProgress;
207 private Vector3 m_moveToPositionTarget; 216 private Vector3 m_moveToPositionTarget;
217 private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
208 218
209 private bool m_followCamAuto; 219 private bool m_followCamAuto;
210 220
211 private int m_movementUpdateCount; 221 private int m_movementUpdateCount;
222 private int m_lastColCount = -1; //KF: Look for Collision chnages
223 private int m_updateCount = 0; //KF: Update Anims for a while
224 private static readonly int UPDATE_COUNT = 10; // how many frames to update for
212 private const int NumMovementsBetweenRayCast = 5; 225 private const int NumMovementsBetweenRayCast = 5;
226 private List<uint> m_lastColliders = new List<uint>();
227
228 private object m_syncRoot = new Object();
213 229
214 private bool CameraConstraintActive; 230 private bool CameraConstraintActive;
215 //private int m_moveToPositionStateStatus; 231 //private int m_moveToPositionStateStatus;
@@ -236,7 +252,9 @@ namespace OpenSim.Region.Framework.Scenes
236 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, 252 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
237 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, 253 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
238 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, 254 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS,
239 DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, 255 DIR_CONTROL_FLAG_BACK_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG,
256 DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS,
257 DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG,
240 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG 258 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
241 } 259 }
242 260
@@ -443,7 +461,8 @@ namespace OpenSim.Region.Framework.Scenes
443 get 461 get
444 { 462 {
445 PhysicsActor actor = m_physicsActor; 463 PhysicsActor actor = m_physicsActor;
446 if (actor != null) 464// if (actor != null)
465 if ((actor != null) && (m_parentID == 0)) // KF Do NOT update m_pos here if Av is sitting!
447 m_pos = actor.Position; 466 m_pos = actor.Position;
448 else 467 else
449 { 468 {
@@ -492,7 +511,8 @@ namespace OpenSim.Region.Framework.Scenes
492 } 511 }
493 } 512 }
494 513
495 m_pos = value; 514 if (m_parentID == 0) // KF Do NOT update m_pos here if Av is sitting!
515 m_pos = value;
496 m_parentPosition = Vector3.Zero; 516 m_parentPosition = Vector3.Zero;
497 } 517 }
498 } 518 }
@@ -536,10 +556,39 @@ namespace OpenSim.Region.Framework.Scenes
536 } 556 }
537 } 557 }
538 558
559 public Quaternion OffsetRotation
560 {
561 get { return m_offsetRotation; }
562 set { m_offsetRotation = value; }
563 }
564
539 public Quaternion Rotation 565 public Quaternion Rotation
540 { 566 {
541 get { return m_bodyRot; } 567 get {
542 set { m_bodyRot = value; } 568 if (m_parentID != 0)
569 {
570 if (m_offsetRotation != null)
571 {
572 return m_offsetRotation;
573 }
574 else
575 {
576 return new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
577 }
578
579 }
580 else
581 {
582 return m_bodyRot;
583 }
584 }
585 set {
586 m_bodyRot = value;
587 if (m_parentID != 0)
588 {
589 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
590 }
591 }
543 } 592 }
544 593
545 public Quaternion PreviousRotation 594 public Quaternion PreviousRotation
@@ -564,11 +613,21 @@ namespace OpenSim.Region.Framework.Scenes
564 613
565 private uint m_parentID; 614 private uint m_parentID;
566 615
616
617 private UUID m_linkedPrim;
618
567 public uint ParentID 619 public uint ParentID
568 { 620 {
569 get { return m_parentID; } 621 get { return m_parentID; }
570 set { m_parentID = value; } 622 set { m_parentID = value; }
571 } 623 }
624
625 public UUID LinkedPrim
626 {
627 get { return m_linkedPrim; }
628 set { m_linkedPrim = value; }
629 }
630
572 public float Health 631 public float Health
573 { 632 {
574 get { return m_health; } 633 get { return m_health; }
@@ -690,7 +749,7 @@ namespace OpenSim.Region.Framework.Scenes
690 CreateSceneViewer(); 749 CreateSceneViewer();
691 m_animator = new ScenePresenceAnimator(this); 750 m_animator = new ScenePresenceAnimator(this);
692 } 751 }
693 752
694 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this() 753 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this()
695 { 754 {
696 m_rootRegionHandle = reginfo.RegionHandle; 755 m_rootRegionHandle = reginfo.RegionHandle;
@@ -722,10 +781,7 @@ namespace OpenSim.Region.Framework.Scenes
722 m_reprioritization_timer.AutoReset = false; 781 m_reprioritization_timer.AutoReset = false;
723 782
724 AdjustKnownSeeds(); 783 AdjustKnownSeeds();
725
726 // TODO: I think, this won't send anything, as we are still a child here...
727 Animator.TrySetMovementAnimation("STAND"); 784 Animator.TrySetMovementAnimation("STAND");
728
729 // we created a new ScenePresence (a new child agent) in a fresh region. 785 // we created a new ScenePresence (a new child agent) in a fresh region.
730 // Request info about all the (root) agents in this region 786 // Request info about all the (root) agents in this region
731 // Note: This won't send data *to* other clients in that region (children don't send) 787 // Note: This won't send data *to* other clients in that region (children don't send)
@@ -776,25 +832,47 @@ namespace OpenSim.Region.Framework.Scenes
776 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT 832 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT
777 Dir_Vectors[4] = Vector3.UnitZ; //UP 833 Dir_Vectors[4] = Vector3.UnitZ; //UP
778 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN 834 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN
779 Dir_Vectors[8] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge 835 Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE
780 Dir_Vectors[6] = Vector3.UnitX*2; //FORWARD 836 Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE
781 Dir_Vectors[7] = -Vector3.UnitX; //BACK 837 Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE
838 Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE
839 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
782 } 840 }
783 841
784 private Vector3[] GetWalkDirectionVectors() 842 private Vector3[] GetWalkDirectionVectors()
785 { 843 {
786 Vector3[] vector = new Vector3[9]; 844 Vector3[] vector = new Vector3[11];
787 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD 845 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD
788 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK 846 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK
789 vector[2] = Vector3.UnitY; //LEFT 847 vector[2] = Vector3.UnitY; //LEFT
790 vector[3] = -Vector3.UnitY; //RIGHT 848 vector[3] = -Vector3.UnitY; //RIGHT
791 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP 849 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP
792 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN 850 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN
793 vector[8] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_Nudge 851 vector[6] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD_NUDGE
794 vector[6] = (new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z) * 2); //FORWARD Nudge 852 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK_NUDGE
795 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK Nudge 853 vector[8] = Vector3.UnitY; //LEFT_NUDGE
854 vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
855 vector[10] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_NUDGE
796 return vector; 856 return vector;
797 } 857 }
858
859 private bool[] GetDirectionIsNudge()
860 {
861 bool[] isNudge = new bool[11];
862 isNudge[0] = false; //FORWARD
863 isNudge[1] = false; //BACK
864 isNudge[2] = false; //LEFT
865 isNudge[3] = false; //RIGHT
866 isNudge[4] = false; //UP
867 isNudge[5] = false; //DOWN
868 isNudge[6] = true; //FORWARD_NUDGE
869 isNudge[7] = true; //BACK_NUDGE
870 isNudge[8] = true; //LEFT_NUDGE
871 isNudge[9] = true; //RIGHT_NUDGE
872 isNudge[10] = true; //DOWN_Nudge
873 return isNudge;
874 }
875
798 876
799 #endregion 877 #endregion
800 878
@@ -856,6 +934,54 @@ namespace OpenSim.Region.Framework.Scenes
856 pos.Y = crossedBorder.BorderLine.Z - 1; 934 pos.Y = crossedBorder.BorderLine.Z - 1;
857 } 935 }
858 936
937 //If they're TP'ing in or logging in, we haven't had time to add any known child regions yet.
938 //This has the unfortunate consequence that if somebody is TP'ing who is already a child agent,
939 //they'll bypass the landing point. But I can't think of any decent way of fixing this.
940 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
941 if (land != null)
942 {
943 if (KnownChildRegionHandles.Count == 0)
944 {
945 //Don't restrict gods, estate managers, or land owners to the TP point. This behaviour mimics agni.
946 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero && UserLevel < 200 && !m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid) && land.LandData.OwnerID != m_uuid)
947 {
948 pos = land.LandData.UserLocation;
949 }
950 }
951
952 land.SendLandUpdateToClient(ControllingClient);
953 }
954
955 if (pos.X < 0 || pos.Y < 0 || pos.Z < 0)
956 {
957 Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128);
958
959 if (pos.X < 0)
960 {
961 emergencyPos.X = (int)Constants.RegionSize + pos.X;
962 if (!(pos.Y < 0))
963 emergencyPos.Y = pos.Y;
964 if (!(pos.Z < 0))
965 emergencyPos.Z = pos.Z;
966 }
967 if (pos.Y < 0)
968 {
969 emergencyPos.Y = (int)Constants.RegionSize + pos.Y;
970 if (!(pos.X < 0))
971 emergencyPos.X = pos.X;
972 if (!(pos.Z < 0))
973 emergencyPos.Z = pos.Z;
974 }
975 if (pos.Z < 0)
976 {
977 emergencyPos.Z = 128;
978 if (!(pos.Y < 0))
979 emergencyPos.Y = pos.Y;
980 if (!(pos.X < 0))
981 emergencyPos.X = pos.X;
982 }
983 }
984
859 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 985 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
860 { 986 {
861 m_log.WarnFormat( 987 m_log.WarnFormat(
@@ -984,12 +1110,17 @@ namespace OpenSim.Region.Framework.Scenes
984 { 1110 {
985 if (PhysicsActor != null) 1111 if (PhysicsActor != null)
986 { 1112 {
987 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; 1113 try
988 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall; 1114 {
989 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); 1115 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
990 m_physicsActor.UnSubscribeEvents(); 1116 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall;
991 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; 1117 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
992 PhysicsActor = null; 1118 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
1119 m_physicsActor.UnSubscribeEvents();
1120 PhysicsActor = null;
1121 }
1122 catch
1123 { }
993 } 1124 }
994 } 1125 }
995 1126
@@ -1000,9 +1131,10 @@ namespace OpenSim.Region.Framework.Scenes
1000 public void Teleport(Vector3 pos) 1131 public void Teleport(Vector3 pos)
1001 { 1132 {
1002 bool isFlying = false; 1133 bool isFlying = false;
1134
1003 if (m_physicsActor != null) 1135 if (m_physicsActor != null)
1004 isFlying = m_physicsActor.Flying; 1136 isFlying = m_physicsActor.Flying;
1005 1137
1006 RemoveFromPhysicalScene(); 1138 RemoveFromPhysicalScene();
1007 Velocity = Vector3.Zero; 1139 Velocity = Vector3.Zero;
1008 AbsolutePosition = pos; 1140 AbsolutePosition = pos;
@@ -1014,6 +1146,7 @@ namespace OpenSim.Region.Framework.Scenes
1014 } 1146 }
1015 1147
1016 SendTerseUpdateToAllClients(); 1148 SendTerseUpdateToAllClients();
1149
1017 } 1150 }
1018 1151
1019 public void TeleportWithMomentum(Vector3 pos) 1152 public void TeleportWithMomentum(Vector3 pos)
@@ -1232,6 +1365,7 @@ namespace OpenSim.Region.Framework.Scenes
1232 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); 1365 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902");
1233 1366
1234 m_pos = m_LastFinitePos; 1367 m_pos = m_LastFinitePos;
1368
1235 if (!m_pos.IsFinite()) 1369 if (!m_pos.IsFinite())
1236 { 1370 {
1237 m_pos.X = 127f; 1371 m_pos.X = 127f;
@@ -1298,7 +1432,6 @@ namespace OpenSim.Region.Framework.Scenes
1298 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); 1432 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback);
1299 } 1433 }
1300 } 1434 }
1301
1302 lock (scriptedcontrols) 1435 lock (scriptedcontrols)
1303 { 1436 {
1304 if (scriptedcontrols.Count > 0) 1437 if (scriptedcontrols.Count > 0)
@@ -1313,6 +1446,9 @@ namespace OpenSim.Region.Framework.Scenes
1313 1446
1314 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) 1447 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
1315 { 1448 {
1449 m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.
1450 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
1451
1316 // TODO: This doesn't prevent the user from walking yet. 1452 // TODO: This doesn't prevent the user from walking yet.
1317 // Setting parent ID would fix this, if we knew what value 1453 // Setting parent ID would fix this, if we knew what value
1318 // to use. Or we could add a m_isSitting variable. 1454 // to use. Or we could add a m_isSitting variable.
@@ -1361,12 +1497,20 @@ namespace OpenSim.Region.Framework.Scenes
1361 if (actor.Flying != oldflying) 1497 if (actor.Flying != oldflying)
1362 update_movementflag = true; 1498 update_movementflag = true;
1363 1499
1500 if (m_animator.m_jumping) // add for jumping
1501 update_movementflag = true;
1502
1364 if (q != m_bodyRot) 1503 if (q != m_bodyRot)
1365 { 1504 {
1366 m_bodyRot = q; 1505 m_bodyRot = q;
1367 update_rotation = true; 1506 update_rotation = true;
1368 } 1507 }
1369 1508
1509 //guilty until proven innocent..
1510 bool Nudging = true;
1511 //Basically, if there is at least one non-nudge control then we don't need
1512 //to worry about stopping the avatar
1513
1370 if (m_parentID == 0) 1514 if (m_parentID == 0)
1371 { 1515 {
1372 bool bAllowUpdateMoveToPosition = false; 1516 bool bAllowUpdateMoveToPosition = false;
@@ -1381,9 +1525,12 @@ namespace OpenSim.Region.Framework.Scenes
1381 else 1525 else
1382 dirVectors = Dir_Vectors; 1526 dirVectors = Dir_Vectors;
1383 1527
1384 // The fact that m_movementflag is a byte needs to be fixed 1528 bool[] isNudge = GetDirectionIsNudge();
1385 // it really should be a uint 1529
1386 uint nudgehack = 250; 1530
1531
1532
1533
1387 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) 1534 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
1388 { 1535 {
1389 if (((uint)flags & (uint)DCF) != 0) 1536 if (((uint)flags & (uint)DCF) != 0)
@@ -1393,40 +1540,28 @@ namespace OpenSim.Region.Framework.Scenes
1393 try 1540 try
1394 { 1541 {
1395 agent_control_v3 += dirVectors[i]; 1542 agent_control_v3 += dirVectors[i];
1396 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); 1543 if (isNudge[i] == false)
1544 {
1545 Nudging = false;
1546 }
1397 } 1547 }
1398 catch (IndexOutOfRangeException) 1548 catch (IndexOutOfRangeException)
1399 { 1549 {
1400 // Why did I get this? 1550 // Why did I get this?
1401 } 1551 }
1402 1552
1403 if ((m_movementflag & (byte)(uint)DCF) == 0) 1553 if ((m_movementflag & (uint)DCF) == 0)
1404 { 1554 {
1405 if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1406 {
1407 m_movementflag |= (byte)nudgehack;
1408 }
1409 m_movementflag += (byte)(uint)DCF; 1555 m_movementflag += (byte)(uint)DCF;
1410 update_movementflag = true; 1556 update_movementflag = true;
1411 } 1557 }
1412 } 1558 }
1413 else 1559 else
1414 { 1560 {
1415 if ((m_movementflag & (byte)(uint)DCF) != 0 || 1561 if ((m_movementflag & (uint)DCF) != 0)
1416 ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1417 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1418 ) // This or is for Nudge forward
1419 { 1562 {
1420 m_movementflag -= ((byte)(uint)DCF); 1563 m_movementflag -= (byte)(uint)DCF;
1421
1422 update_movementflag = true; 1564 update_movementflag = true;
1423 /*
1424 if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1425 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1426 {
1427 m_log.Debug("Removed Hack flag");
1428 }
1429 */
1430 } 1565 }
1431 else 1566 else
1432 { 1567 {
@@ -1435,7 +1570,6 @@ namespace OpenSim.Region.Framework.Scenes
1435 } 1570 }
1436 i++; 1571 i++;
1437 } 1572 }
1438
1439 //Paupaw:Do Proper PID for Autopilot here 1573 //Paupaw:Do Proper PID for Autopilot here
1440 if (bResetMoveToPosition) 1574 if (bResetMoveToPosition)
1441 { 1575 {
@@ -1470,6 +1604,9 @@ namespace OpenSim.Region.Framework.Scenes
1470 // Ignore z component of vector 1604 // Ignore z component of vector
1471 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); 1605 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f);
1472 LocalVectorToTarget2D.Normalize(); 1606 LocalVectorToTarget2D.Normalize();
1607
1608 //We're not nudging
1609 Nudging = false;
1473 agent_control_v3 += LocalVectorToTarget2D; 1610 agent_control_v3 += LocalVectorToTarget2D;
1474 1611
1475 // update avatar movement flags. the avatar coordinate system is as follows: 1612 // update avatar movement flags. the avatar coordinate system is as follows:
@@ -1560,13 +1697,13 @@ namespace OpenSim.Region.Framework.Scenes
1560 // m_log.DebugFormat( 1697 // m_log.DebugFormat(
1561 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); 1698 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3);
1562 1699
1563 AddNewMovement(agent_control_v3, q); 1700 AddNewMovement(agent_control_v3, q, Nudging);
1564 1701
1565 1702
1566 } 1703 }
1567 } 1704 }
1568 1705
1569 if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) 1706 if (update_movementflag && !SitGround)
1570 Animator.UpdateMovementAnimations(); 1707 Animator.UpdateMovementAnimations();
1571 1708
1572 m_scene.EventManager.TriggerOnClientMovement(this); 1709 m_scene.EventManager.TriggerOnClientMovement(this);
@@ -1581,7 +1718,6 @@ namespace OpenSim.Region.Framework.Scenes
1581 m_sitAtAutoTarget = false; 1718 m_sitAtAutoTarget = false;
1582 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; 1719 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default;
1583 //proxy.PCode = (byte)PCode.ParticleSystem; 1720 //proxy.PCode = (byte)PCode.ParticleSystem;
1584
1585 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); 1721 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy);
1586 proxyObjectGroup.AttachToScene(m_scene); 1722 proxyObjectGroup.AttachToScene(m_scene);
1587 1723
@@ -1622,8 +1758,8 @@ namespace OpenSim.Region.Framework.Scenes
1622 return; 1758 return;
1623 } 1759 }
1624 m_moveToPositionInProgress = true; 1760 m_moveToPositionInProgress = true;
1625 m_moveToPositionTarget = new Vector3(locx, locy, locz); 1761 m_moveToPositionTarget = new Vector3(locx, locy, locz + (m_appearance.AvatarHeight / 2.0f));
1626 } 1762 }
1627 catch (Exception ex) 1763 catch (Exception ex)
1628 { 1764 {
1629 //Why did I get this error? 1765 //Why did I get this error?
@@ -1645,7 +1781,7 @@ namespace OpenSim.Region.Framework.Scenes
1645 Velocity = Vector3.Zero; 1781 Velocity = Vector3.Zero;
1646 SendAvatarDataToAllAgents(); 1782 SendAvatarDataToAllAgents();
1647 1783
1648 //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); 1784 HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); //KF ??
1649 } 1785 }
1650 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); 1786 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false);
1651 m_requestedSitTargetUUID = UUID.Zero; 1787 m_requestedSitTargetUUID = UUID.Zero;
@@ -1682,25 +1818,22 @@ namespace OpenSim.Region.Framework.Scenes
1682 1818
1683 if (m_parentID != 0) 1819 if (m_parentID != 0)
1684 { 1820 {
1685 m_log.Debug("StandupCode Executed"); 1821 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
1686 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
1687 if (part != null) 1822 if (part != null)
1688 { 1823 {
1824 part.TaskInventory.LockItemsForRead(true);
1689 TaskInventoryDictionary taskIDict = part.TaskInventory; 1825 TaskInventoryDictionary taskIDict = part.TaskInventory;
1690 if (taskIDict != null) 1826 if (taskIDict != null)
1691 { 1827 {
1692 lock (taskIDict) 1828 foreach (UUID taskID in taskIDict.Keys)
1693 { 1829 {
1694 foreach (UUID taskID in taskIDict.Keys) 1830 UnRegisterControlEventsToScript(LocalId, taskID);
1695 { 1831 taskIDict[taskID].PermsMask &= ~(
1696 UnRegisterControlEventsToScript(LocalId, taskID); 1832 2048 | //PERMISSION_CONTROL_CAMERA
1697 taskIDict[taskID].PermsMask &= ~( 1833 4); // PERMISSION_TAKE_CONTROLS
1698 2048 | //PERMISSION_CONTROL_CAMERA
1699 4); // PERMISSION_TAKE_CONTROLS
1700 }
1701 } 1834 }
1702
1703 } 1835 }
1836 part.TaskInventory.LockItemsForRead(false);
1704 // Reset sit target. 1837 // Reset sit target.
1705 if (part.GetAvatarOnSitTarget() == UUID) 1838 if (part.GetAvatarOnSitTarget() == UUID)
1706 part.SitTargetAvatar = UUID.Zero; 1839 part.SitTargetAvatar = UUID.Zero;
@@ -1709,16 +1842,55 @@ namespace OpenSim.Region.Framework.Scenes
1709 m_parentPosition = part.GetWorldPosition(); 1842 m_parentPosition = part.GetWorldPosition();
1710 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1843 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1711 } 1844 }
1845 // part.GetWorldRotation() is the rotation of the object being sat on
1846 // Rotation is the sittiing Av's rotation
1847
1848 Quaternion partRot;
1849// if (part.LinkNum == 1)
1850// { // Root prim of linkset
1851// partRot = part.ParentGroup.RootPart.RotationOffset;
1852// }
1853// else
1854// { // single or child prim
1855
1856// }
1857 if (part == null) //CW: Part may be gone. llDie() for example.
1858 {
1859 partRot = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1860 }
1861 else
1862 {
1863 partRot = part.GetWorldRotation();
1864 }
1865
1866 Quaternion partIRot = Quaternion.Inverse(partRot);
1712 1867
1868 Quaternion avatarRot = Quaternion.Inverse(Quaternion.Inverse(Rotation) * partIRot); // world or. of the av
1869 Vector3 avStandUp = new Vector3(1.0f, 0f, 0f) * avatarRot; // 1M infront of av
1870
1871
1713 if (m_physicsActor == null) 1872 if (m_physicsActor == null)
1714 { 1873 {
1715 AddToPhysicalScene(false); 1874 AddToPhysicalScene(false);
1716 } 1875 }
1717 1876 //CW: If the part isn't null then we can set the current position
1718 m_pos += m_parentPosition + new Vector3(0.0f, 0.0f, 2.0f*m_sitAvatarHeight); 1877 if (part != null)
1719 m_parentPosition = Vector3.Zero; 1878 {
1720 1879 Vector3 avWorldStandUp = avStandUp + part.GetWorldPosition() + ((m_pos - part.OffsetPosition) * partRot); // + av sit offset!
1721 m_parentID = 0; 1880 AbsolutePosition = avWorldStandUp; //KF: Fix stand up.
1881 part.IsOccupied = false;
1882 part.ParentGroup.DeleteAvatar(ControllingClient.AgentId);
1883 }
1884 else
1885 {
1886 //CW: Since the part doesn't exist, a coarse standup position isn't an issue
1887 AbsolutePosition = m_lastWorldPosition;
1888 }
1889
1890 m_parentPosition = Vector3.Zero;
1891 m_parentID = 0;
1892 m_linkedPrim = UUID.Zero;
1893 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1722 SendAvatarDataToAllAgents(); 1894 SendAvatarDataToAllAgents();
1723 m_requestedSitTargetID = 0; 1895 m_requestedSitTargetID = 0;
1724 if (m_physicsActor != null && m_appearance != null) 1896 if (m_physicsActor != null && m_appearance != null)
@@ -1727,7 +1899,6 @@ namespace OpenSim.Region.Framework.Scenes
1727 SetHeight(m_appearance.AvatarHeight); 1899 SetHeight(m_appearance.AvatarHeight);
1728 } 1900 }
1729 } 1901 }
1730
1731 Animator.TrySetMovementAnimation("STAND"); 1902 Animator.TrySetMovementAnimation("STAND");
1732 } 1903 }
1733 1904
@@ -1758,13 +1929,9 @@ namespace OpenSim.Region.Framework.Scenes
1758 Vector3 avSitOffSet = part.SitTargetPosition; 1929 Vector3 avSitOffSet = part.SitTargetPosition;
1759 Quaternion avSitOrientation = part.SitTargetOrientation; 1930 Quaternion avSitOrientation = part.SitTargetOrientation;
1760 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 1931 UUID avOnTargetAlready = part.GetAvatarOnSitTarget();
1761 1932 bool SitTargetOccupied = (avOnTargetAlready != UUID.Zero);
1762 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 1933 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1763 bool SitTargetisSet = 1934 if (SitTargetisSet && !SitTargetOccupied)
1764 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 1f &&
1765 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f));
1766
1767 if (SitTargetisSet && SitTargetUnOccupied)
1768 { 1935 {
1769 //switch the target to this prim 1936 //switch the target to this prim
1770 return part; 1937 return part;
@@ -1778,85 +1945,167 @@ namespace OpenSim.Region.Framework.Scenes
1778 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) 1945 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation)
1779 { 1946 {
1780 bool autopilot = true; 1947 bool autopilot = true;
1948 Vector3 autopilotTarget = new Vector3();
1949 Quaternion sitOrientation = Quaternion.Identity;
1781 Vector3 pos = new Vector3(); 1950 Vector3 pos = new Vector3();
1782 Quaternion sitOrientation = pSitOrientation;
1783 Vector3 cameraEyeOffset = Vector3.Zero; 1951 Vector3 cameraEyeOffset = Vector3.Zero;
1784 Vector3 cameraAtOffset = Vector3.Zero; 1952 Vector3 cameraAtOffset = Vector3.Zero;
1785 bool forceMouselook = false; 1953 bool forceMouselook = false;
1786 1954
1787 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); 1955 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1788 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 1956 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1789 if (part != null) 1957 if (part == null) return;
1790 { 1958
1791 // TODO: determine position to sit at based on scene geometry; don't trust offset from client 1959 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
1792 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it 1960 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
1793 1961
1794 // Is a sit target available? 1962 // part is the prim to sit on
1795 Vector3 avSitOffSet = part.SitTargetPosition; 1963 // offset is the world-ref vector distance from that prim center to the click-spot
1796 Quaternion avSitOrientation = part.SitTargetOrientation; 1964 // UUID is the UUID of the Avatar doing the clicking
1797 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 1965
1798 1966 m_avInitialPos = AbsolutePosition; // saved to calculate unscripted sit rotation
1799 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 1967
1800 bool SitTargetisSet = 1968 // Is a sit target available?
1801 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && 1969 Vector3 avSitOffSet = part.SitTargetPosition;
1802 ( 1970 Quaternion avSitOrientation = part.SitTargetOrientation;
1803 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 1f // Valid Zero Rotation quaternion 1971
1804 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point 1972 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1805 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion 1973 // Quaternion partIRot = Quaternion.Inverse(part.GetWorldRotation());
1806 ) 1974 Quaternion partRot;
1807 )); 1975// if (part.LinkNum == 1)
1808 1976// { // Root prim of linkset
1809 if (SitTargetisSet && SitTargetUnOccupied) 1977// partRot = part.ParentGroup.RootPart.RotationOffset;
1810 { 1978// }
1811 part.SitTargetAvatar = UUID; 1979// else
1812 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); 1980// { // single or child prim
1813 sitOrientation = avSitOrientation; 1981 partRot = part.GetWorldRotation();
1814 autopilot = false; 1982// }
1815 } 1983 Quaternion partIRot = Quaternion.Inverse(partRot);
1816 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); 1984//Console.WriteLine("SendSitResponse offset=" + offset + " Occup=" + part.IsOccupied + " TargSet=" + SitTargetisSet);
1817 1985 // Sit analysis rewritten by KF 091125
1818 pos = part.AbsolutePosition + offset; 1986 if (SitTargetisSet) // scipted sit
1819 //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1) 1987 {
1820 //{ 1988 if (!part.IsOccupied)
1821 // offset = pos; 1989 {
1822 //autopilot = false; 1990//Console.WriteLine("Scripted, unoccupied");
1823 //} 1991 part.SitTargetAvatar = UUID; // set that Av will be on it
1824 if (m_physicsActor != null) 1992 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); // change ofset to the scripted one
1825 { 1993
1826 // If we're not using the client autopilot, we're immediately warping the avatar to the location 1994 Quaternion nrot = avSitOrientation;
1827 // We can remove the physicsActor until they stand up. 1995 if (!part.IsRoot)
1828 m_sitAvatarHeight = m_physicsActor.Size.Z;
1829
1830 if (autopilot)
1831 { 1996 {
1832 if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5) 1997 nrot = part.RotationOffset * avSitOrientation;
1833 {
1834 autopilot = false;
1835
1836 RemoveFromPhysicalScene();
1837 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
1838 }
1839 } 1998 }
1840 else 1999 sitOrientation = nrot; // Change rotatione to the scripted one
2000 OffsetRotation = nrot;
2001 autopilot = false; // Jump direct to scripted llSitPos()
2002 }
2003 else
2004 {
2005//Console.WriteLine("Scripted, occupied");
2006 return;
2007 }
2008 }
2009 else // Not Scripted
2010 {
2011 if ( (Math.Abs(offset.X) > 0.1f) || (Math.Abs(offset.Y) > 0.1f) ) // Changed 0.5M to 0.1M as they want to be able to sit close together
2012 {
2013 // large prim & offset, ignore if other Avs sitting
2014// offset.Z -= 0.05f;
2015 m_avUnscriptedSitPos = offset * partIRot; // (non-zero) sit where clicked
2016 autopilotTarget = part.AbsolutePosition + offset; // World location of clicked point
2017
2018//Console.WriteLine(" offset ={0}", offset);
2019//Console.WriteLine(" UnscriptedSitPos={0}", m_avUnscriptedSitPos);
2020//Console.WriteLine(" autopilotTarget={0}", autopilotTarget);
2021
2022 }
2023 else // small offset
2024 {
2025//Console.WriteLine("Small offset");
2026 if (!part.IsOccupied)
2027 {
2028 m_avUnscriptedSitPos = Vector3.Zero; // Zero = Sit on prim center
2029 autopilotTarget = part.AbsolutePosition;
2030//Console.WriteLine("UsSmall autopilotTarget={0}", autopilotTarget);
2031 }
2032 else return; // occupied small
2033 } // end large/small
2034 } // end Scripted/not
2035
2036 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2037
2038 cameraAtOffset = part.GetCameraAtOffset();
2039 cameraEyeOffset = part.GetCameraEyeOffset();
2040 forceMouselook = part.GetForceMouselook();
2041 if(cameraAtOffset == Vector3.Zero) cameraAtOffset = new Vector3(0f, 0f, 0.1f); //
2042 if(cameraEyeOffset == Vector3.Zero) cameraEyeOffset = new Vector3(0f, 0f, 0.1f); //
2043
2044 if (m_physicsActor != null)
2045 {
2046 // If we're not using the client autopilot, we're immediately warping the avatar to the location
2047 // We can remove the physicsActor until they stand up.
2048 m_sitAvatarHeight = m_physicsActor.Size.Z;
2049 if (autopilot)
2050 { // its not a scripted sit
2051// if (Util.GetDistanceTo(AbsolutePosition, autopilotTarget) < 4.5)
2052 if( (Math.Abs(AbsolutePosition.X - autopilotTarget.X) < 256.0f) && (Math.Abs(AbsolutePosition.Y - autopilotTarget.Y) < 256.0f) )
1841 { 2053 {
2054 autopilot = false; // close enough
2055 m_lastWorldPosition = m_pos; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2056 Not using the part's position because returning the AV to the last known standing
2057 position is likely to be more friendly, isn't it? */
1842 RemoveFromPhysicalScene(); 2058 RemoveFromPhysicalScene();
1843 } 2059 Velocity = Vector3.Zero;
2060 AbsolutePosition = autopilotTarget + new Vector3(0.0f, 0.0f, (m_sitAvatarHeight / 2.0f)); // Warp av to over sit target
2061 } // else the autopilot will get us close
2062 }
2063 else
2064 { // its a scripted sit
2065 m_lastWorldPosition = part.AbsolutePosition; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2066 I *am* using the part's position this time because we have no real idea how far away
2067 the avatar is from the sit target. */
2068 RemoveFromPhysicalScene();
2069 Velocity = Vector3.Zero;
1844 } 2070 }
1845
1846 cameraAtOffset = part.GetCameraAtOffset();
1847 cameraEyeOffset = part.GetCameraEyeOffset();
1848 forceMouselook = part.GetForceMouselook();
1849 } 2071 }
1850 2072 else return; // physactor is null!
1851 ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); 2073
1852 m_requestedSitTargetUUID = targetID; 2074 Vector3 offsetr; // = offset * partIRot;
2075 // KF: In a linkset, offsetr needs to be relative to the group root! 091208
2076 // offsetr = (part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) + (offset * partIRot);
2077 // if (part.LinkNum < 2) 091216 All this was necessary because of the GetWorldRotation error.
2078 // { // Single, or Root prim of linkset, target is ClickOffset * RootRot
2079 //offsetr = offset * partIRot;
2080//
2081 // else
2082 // { // Child prim, offset is (ChildOffset * RootRot) + (ClickOffset * ChildRot)
2083 // offsetr = //(part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) +
2084 // (offset * partRot);
2085 // }
2086
2087//Console.WriteLine(" ");
2088//Console.WriteLine("link number ={0}", part.LinkNum);
2089//Console.WriteLine("Prim offset ={0}", part.OffsetPosition );
2090//Console.WriteLine("Root Rotate ={0}", part.ParentGroup.RootPart.RotationOffset);
2091//Console.WriteLine("Click offst ={0}", offset);
2092//Console.WriteLine("Prim Rotate ={0}", part.GetWorldRotation());
2093//Console.WriteLine("offsetr ={0}", offsetr);
2094//Console.WriteLine("Camera At ={0}", cameraAtOffset);
2095//Console.WriteLine("Camera Eye ={0}", cameraEyeOffset);
2096
2097 //NOTE: SendSitResponse should be relative to the GROUP *NOT* THE PRIM if we're sitting on a child
2098 ControllingClient.SendSitResponse(part.ParentGroup.UUID, ((offset * part.RotationOffset) + part.OffsetPosition), sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook);
2099
2100 m_requestedSitTargetUUID = part.UUID; //KF: Correct autopilot target
1853 // This calls HandleAgentSit twice, once from here, and the client calls 2101 // This calls HandleAgentSit twice, once from here, and the client calls
1854 // HandleAgentSit itself after it gets to the location 2102 // HandleAgentSit itself after it gets to the location
1855 // It doesn't get to the location until we've moved them there though 2103 // It doesn't get to the location until we've moved them there though
1856 // which happens in HandleAgentSit :P 2104 // which happens in HandleAgentSit :P
1857 m_autopilotMoving = autopilot; 2105 m_autopilotMoving = autopilot;
1858 m_autoPilotTarget = pos; 2106 m_autoPilotTarget = autopilotTarget;
1859 m_sitAtAutoTarget = autopilot; 2107 m_sitAtAutoTarget = autopilot;
2108 m_initialSitTarget = autopilotTarget;
1860 if (!autopilot) 2109 if (!autopilot)
1861 HandleAgentSit(remoteClient, UUID); 2110 HandleAgentSit(remoteClient, UUID);
1862 } 2111 }
@@ -2151,47 +2400,130 @@ namespace OpenSim.Region.Framework.Scenes
2151 { 2400 {
2152 if (part != null) 2401 if (part != null)
2153 { 2402 {
2403//Console.WriteLine("Link #{0}, Rot {1}", part.LinkNum, part.GetWorldRotation());
2154 if (part.GetAvatarOnSitTarget() == UUID) 2404 if (part.GetAvatarOnSitTarget() == UUID)
2155 { 2405 {
2406//Console.WriteLine("Scripted Sit");
2407 // Scripted sit
2156 Vector3 sitTargetPos = part.SitTargetPosition; 2408 Vector3 sitTargetPos = part.SitTargetPosition;
2157 Quaternion sitTargetOrient = part.SitTargetOrientation; 2409 Quaternion sitTargetOrient = part.SitTargetOrientation;
2158
2159 //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0);
2160 //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w);
2161
2162 //Quaternion result = (sitTargetOrient * vq) * nq;
2163
2164 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z); 2410 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z);
2165 m_pos += SIT_TARGET_ADJUSTMENT; 2411 m_pos += SIT_TARGET_ADJUSTMENT;
2412 if (!part.IsRoot)
2413 {
2414 m_pos *= part.RotationOffset;
2415 }
2166 m_bodyRot = sitTargetOrient; 2416 m_bodyRot = sitTargetOrient;
2167 //Rotation = sitTargetOrient;
2168 m_parentPosition = part.AbsolutePosition; 2417 m_parentPosition = part.AbsolutePosition;
2169 2418 part.IsOccupied = true;
2170 //SendTerseUpdateToAllClients(); 2419 part.ParentGroup.AddAvatar(agentID);
2171 } 2420 }
2172 else 2421 else
2173 { 2422 {
2174 m_pos -= part.AbsolutePosition; 2423 // if m_avUnscriptedSitPos is zero then Av sits above center
2424 // Else Av sits at m_avUnscriptedSitPos
2425
2426 // Non-scripted sit by Kitto Flora 21Nov09
2427 // Calculate angle of line from prim to Av
2428 Quaternion partIRot;
2429// if (part.LinkNum == 1)
2430// { // Root prim of linkset
2431// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2432// }
2433// else
2434// { // single or child prim
2435 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2436// }
2437 Vector3 sitTargetPos= part.AbsolutePosition + m_avUnscriptedSitPos;
2438 float y_diff = (m_avInitialPos.Y - sitTargetPos.Y);
2439 float x_diff = ( m_avInitialPos.X - sitTargetPos.X);
2440 if(Math.Abs(x_diff) < 0.001f) x_diff = 0.001f; // avoid div by 0
2441 if(Math.Abs(y_diff) < 0.001f) y_diff = 0.001f; // avoid pol flip at 0
2442 float sit_angle = (float)Math.Atan2( (double)y_diff, (double)x_diff);
2443 // NOTE: when sitting m_ pos and m_bodyRot are *relative* to the prim location/rotation, not 'World'.
2444 // Av sits at world euler <0,0, z>, translated by part rotation
2445 m_bodyRot = partIRot * Quaternion.CreateFromEulers(0f, 0f, sit_angle); // sit at 0,0,inv-click
2446
2175 m_parentPosition = part.AbsolutePosition; 2447 m_parentPosition = part.AbsolutePosition;
2176 } 2448 part.IsOccupied = true;
2449 part.ParentGroup.AddAvatar(agentID);
2450 m_pos = new Vector3(0f, 0f, 0.05f) + // corrections to get Sit Animation
2451 (new Vector3(0.0f, 0f, 0.61f) * partIRot) + // located on center
2452 (new Vector3(0.34f, 0f, 0.0f) * m_bodyRot) +
2453 m_avUnscriptedSitPos; // adds click offset, if any
2454 //Set up raytrace to find top surface of prim
2455 Vector3 size = part.Scale;
2456 float mag = 2.0f; // 0.1f + (float)Math.Sqrt((size.X * size.X) + (size.Y * size.Y) + (size.Z * size.Z));
2457 Vector3 start = part.AbsolutePosition + new Vector3(0f, 0f, mag);
2458 Vector3 down = new Vector3(0f, 0f, -1f);
2459//Console.WriteLine("st={0} do={1} ma={2}", start, down, mag);
2460 m_scene.PhysicsScene.RaycastWorld(
2461 start, // Vector3 position,
2462 down, // Vector3 direction,
2463 mag, // float length,
2464 SitAltitudeCallback); // retMethod
2465 } // end scripted/not
2177 } 2466 }
2178 else 2467 else // no Av
2179 { 2468 {
2180 return; 2469 return;
2181 } 2470 }
2182 } 2471 }
2183 m_parentID = m_requestedSitTargetID;
2184 2472
2473 //We want our offsets to reference the root prim, not the child we may have sat on
2474 if (!part.IsRoot)
2475 {
2476 m_parentID = part.ParentGroup.RootPart.LocalId;
2477 m_pos += part.OffsetPosition;
2478 }
2479 else
2480 {
2481 m_parentID = m_requestedSitTargetID;
2482 }
2483
2484 m_linkedPrim = part.UUID;
2485 if (part.GetAvatarOnSitTarget() != UUID)
2486 {
2487 m_offsetRotation = m_offsetRotation / part.RotationOffset;
2488 }
2185 Velocity = Vector3.Zero; 2489 Velocity = Vector3.Zero;
2186 RemoveFromPhysicalScene(); 2490 RemoveFromPhysicalScene();
2187
2188 Animator.TrySetMovementAnimation(sitAnimation); 2491 Animator.TrySetMovementAnimation(sitAnimation);
2189 SendAvatarDataToAllAgents(); 2492 SendAvatarDataToAllAgents();
2190 // This may seem stupid, but Our Full updates don't send avatar rotation :P
2191 // So we're also sending a terse update (which has avatar rotation)
2192 // [Update] We do now.
2193 //SendTerseUpdateToAllClients(); 2493 //SendTerseUpdateToAllClients();
2194 } 2494 }
2495
2496 public void SitAltitudeCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
2497 {
2498 // KF: 091202 There appears to be a bug in Prim Edit Size - the process sometimes make a prim that RayTrace no longer
2499 // sees. Take/re-rez, or sim restart corrects the condition. Result of bug is incorrect sit height.
2500 if(hitYN)
2501 {
2502 // m_pos = Av offset from prim center to make look like on center
2503 // m_parentPosition = Actual center pos of prim
2504 // collisionPoint = spot on prim where we want to sit
2505 // collisionPoint.Z = global sit surface height
2506 SceneObjectPart part = m_scene.GetSceneObjectPart(localid);
2507 Quaternion partIRot;
2508// if (part.LinkNum == 1)
2509/// { // Root prim of linkset
2510// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2511// }
2512// else
2513// { // single or child prim
2514 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2515// }
2516 if (m_initialSitTarget != null)
2517 {
2518 float offZ = collisionPoint.Z - m_initialSitTarget.Z;
2519 Vector3 offset = new Vector3(0.0f, 0.0f, offZ) * partIRot; // Altitude correction
2520 //Console.WriteLine("sitPoint={0}, offset={1}", sitPoint, offset);
2521 m_pos += offset;
2522 // ControllingClient.SendClearFollowCamProperties(part.UUID);
2523 }
2524
2525 }
2526 } // End SitAltitudeCallback KF.
2195 2527
2196 /// <summary> 2528 /// <summary>
2197 /// Event handler for the 'Always run' setting on the client 2529 /// Event handler for the 'Always run' setting on the client
@@ -2221,12 +2553,13 @@ namespace OpenSim.Region.Framework.Scenes
2221 /// </summary> 2553 /// </summary>
2222 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> 2554 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2223 /// <param name="rotation">The direction in which this avatar should now face. 2555 /// <param name="rotation">The direction in which this avatar should now face.
2224 public void AddNewMovement(Vector3 vec, Quaternion rotation) 2556 public void AddNewMovement(Vector3 vec, Quaternion rotation, bool Nudging)
2225 { 2557 {
2226 if (m_isChildAgent) 2558 if (m_isChildAgent)
2227 { 2559 {
2228 // WHAT??? 2560 // WHAT???
2229 m_log.Debug("[SCENEPRESENCE]: AddNewMovement() called on child agent, making root agent!"); 2561 m_log.Debug("[SCENEPRESENCE]: AddNewMovement() called on child agent");
2562
2230 return; 2563 return;
2231 } 2564 }
2232 2565
@@ -2235,15 +2568,26 @@ namespace OpenSim.Region.Framework.Scenes
2235 Rotation = rotation; 2568 Rotation = rotation;
2236 Vector3 direc = vec * rotation; 2569 Vector3 direc = vec * rotation;
2237 direc.Normalize(); 2570 direc.Normalize();
2571 PhysicsActor actor = m_physicsActor;
2572
2573 if (actor.Flying != m_flyingOld) // add for fly velocity control
2574 {
2575 m_flyingOld = actor.Flying; // add for fly velocity control
2576 if (!actor.Flying) m_wasFlying = true; // add for fly velocity control
2577 }
2578
2579 if (m_physicsActor.IsColliding == true) m_wasFlying = false; // add for fly velocity control
2580
2581 if ((vec.Z == 0f) && !actor.Flying) direc.Z = 0f; // Prevent camera WASD up.
2238 2582
2239 direc *= 0.03f * 128f * m_speedModifier; 2583 direc *= 0.03f * 128f * m_speedModifier;
2240 2584
2241 PhysicsActor actor = m_physicsActor;
2242 if (actor != null) 2585 if (actor != null)
2243 { 2586 {
2244 if (actor.Flying) 2587 if (actor.Flying)
2245 { 2588 {
2246 direc *= 4.0f; 2589// rm speed mod direc *= 4.0f;
2590 direc *= 5.2f; // for speed mod
2247 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 2591 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
2248 //bool colliding = (m_physicsActor.IsColliding==true); 2592 //bool colliding = (m_physicsActor.IsColliding==true);
2249 //if (controlland) 2593 //if (controlland)
@@ -2256,22 +2600,34 @@ namespace OpenSim.Region.Framework.Scenes
2256 // m_log.Info("[AGENT]: Stop FLying"); 2600 // m_log.Info("[AGENT]: Stop FLying");
2257 //} 2601 //}
2258 } 2602 }
2603 if (Animator.m_falling && m_wasFlying) // if falling from flying, disable motion add
2604 {
2605 direc *= 0.0f;
2606 }
2607 /* This jumping section removed to SPA
2259 else if (!actor.Flying && actor.IsColliding) 2608 else if (!actor.Flying && actor.IsColliding)
2260 { 2609 {
2261 if (direc.Z > 2.0f) 2610 if (direc.Z > 2.0f)
2262 { 2611 {
2263 direc.Z *= 3.0f; 2612 if(m_animator.m_animTickJump == -1)
2264 2613 {
2265 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. 2614 direc.Z *= 3.0f; // jump
2266 Animator.TrySetMovementAnimation("PREJUMP"); 2615 }
2267 Animator.TrySetMovementAnimation("JUMP"); 2616 else
2617 {
2618 direc.Z *= 0.1f; // prejump
2619 }
2620 / * Animations are controlled via GetMovementAnimation() in ScenePresenceAnimator.cs
2621 Animator.TrySetMovementAnimation("PREJUMP");
2622 Animator.TrySetMovementAnimation("JUMP");
2623 * /
2268 } 2624 }
2269 } 2625 } */
2270 } 2626 }
2271 2627
2272 // TODO: Add the force instead of only setting it to support multiple forces per frame? 2628 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2273 m_forceToApply = direc; 2629 m_forceToApply = direc;
2274 2630 m_isNudging = Nudging;
2275 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2631 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2276 } 2632 }
2277 2633
@@ -2320,6 +2676,9 @@ namespace OpenSim.Region.Framework.Scenes
2320 2676
2321 CheckForSignificantMovement(); // sends update to the modules. 2677 CheckForSignificantMovement(); // sends update to the modules.
2322 } 2678 }
2679
2680 //Sending prim updates AFTER the avatar terse updates are sent
2681 SendPrimUpdates();
2323 } 2682 }
2324 2683
2325 #endregion 2684 #endregion
@@ -3083,6 +3442,7 @@ namespace OpenSim.Region.Framework.Scenes
3083 m_callbackURI = cAgent.CallbackURI; 3442 m_callbackURI = cAgent.CallbackURI;
3084 3443
3085 m_pos = cAgent.Position; 3444 m_pos = cAgent.Position;
3445
3086 m_velocity = cAgent.Velocity; 3446 m_velocity = cAgent.Velocity;
3087 m_CameraCenter = cAgent.Center; 3447 m_CameraCenter = cAgent.Center;
3088 m_CameraAtAxis = cAgent.AtAxis; 3448 m_CameraAtAxis = cAgent.AtAxis;
@@ -3201,20 +3561,45 @@ namespace OpenSim.Region.Framework.Scenes
3201 /// </summary> 3561 /// </summary>
3202 public override void UpdateMovement() 3562 public override void UpdateMovement()
3203 { 3563 {
3204 if (m_forceToApply.HasValue) 3564 if (Animator!=null) // add for jumping
3205 { 3565 { // add for jumping
3206 Vector3 force = m_forceToApply.Value; 3566 // if (!m_animator.m_jumping) // add for jumping
3567 // { // add for jumping
3207 3568
3208 m_updateflag = true; 3569 if (m_forceToApply.HasValue) // this section realigned
3209 3570 {
3210 // The magic constant 0.95f seems to make walking feel less jerky,
3211 // probably because it hackishly accounts for the overall latency of
3212 // these Velocity updates -- Diva
3213 Velocity = force * .95F;
3214 3571
3215 m_forceToApply = null; 3572 Vector3 force = m_forceToApply.Value;
3216 } 3573 m_updateflag = true;
3217 } 3574if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3575 Velocity = force;
3576//Console.WriteLine("UM1 {0}", Velocity);
3577 m_forceToApply = null;
3578 }
3579 else
3580 {
3581 if (m_isNudging)
3582 {
3583 Vector3 force = Vector3.Zero;
3584
3585 m_updateflag = true;
3586if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3587 Velocity = force;
3588//Console.WriteLine("UM2 {0}", Velocity);
3589 m_isNudging = false;
3590 m_updateCount = UPDATE_COUNT; //KF: Update anims to pickup "STAND"
3591 }
3592 else // add for jumping
3593 { // add for jumping
3594 Vector3 force = Vector3.Zero; // add for jumping
3595if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3596//Console.WriteLine("UM3 {0}", Velocity);
3597 Velocity = force; // add for jumping
3598 }
3599 }
3600 // } // end realign
3601 } // add for jumping
3602 } // add for jumping
3218 3603
3219 /// <summary> 3604 /// <summary>
3220 /// Adds a physical representation of the avatar to the Physics plugin 3605 /// Adds a physical representation of the avatar to the Physics plugin
@@ -3228,10 +3613,8 @@ namespace OpenSim.Region.Framework.Scenes
3228 3613
3229 Vector3 pVec = AbsolutePosition; 3614 Vector3 pVec = AbsolutePosition;
3230 3615
3231 // Old bug where the height was in centimeters instead of meters
3232 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec, 3616 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec,
3233 new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying); 3617 new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying);
3234
3235 scene.AddPhysicsActorTaint(m_physicsActor); 3618 scene.AddPhysicsActorTaint(m_physicsActor);
3236 //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; 3619 //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
3237 m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; 3620 m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
@@ -3255,18 +3638,29 @@ namespace OpenSim.Region.Framework.Scenes
3255 { 3638 {
3256 if (e == null) 3639 if (e == null)
3257 return; 3640 return;
3258 3641
3259 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) 3642 // The Physics Scene will send (spam!) updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3260 // The Physics Scene will send updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3261 // as of this comment the interval is set in AddToPhysicalScene 3643 // as of this comment the interval is set in AddToPhysicalScene
3262 if (Animator!=null) 3644 if (Animator!=null)
3263 Animator.UpdateMovementAnimations(); 3645 {
3646 if (m_updateCount > 0) //KF: DO NOT call UpdateMovementAnimations outside of the m_updateCount wrapper,
3647 { // else its will lock out other animation changes, like ground sit.
3648 Animator.UpdateMovementAnimations();
3649 m_updateCount--;
3650 }
3651 }
3264 3652
3265 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 3653 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3266 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 3654 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3267 3655
3268 CollisionPlane = Vector4.UnitW; 3656 CollisionPlane = Vector4.UnitW;
3269 3657
3658 if (m_lastColCount != coldata.Count)
3659 {
3660 m_updateCount = UPDATE_COUNT;
3661 m_lastColCount = coldata.Count;
3662 }
3663
3270 if (coldata.Count != 0 && Animator != null) 3664 if (coldata.Count != 0 && Animator != null)
3271 { 3665 {
3272 switch (Animator.CurrentMovementAnimation) 3666 switch (Animator.CurrentMovementAnimation)
@@ -3296,6 +3690,148 @@ namespace OpenSim.Region.Framework.Scenes
3296 } 3690 }
3297 } 3691 }
3298 3692
3693 List<uint> thisHitColliders = new List<uint>();
3694 List<uint> endedColliders = new List<uint>();
3695 List<uint> startedColliders = new List<uint>();
3696
3697 foreach (uint localid in coldata.Keys)
3698 {
3699 thisHitColliders.Add(localid);
3700 if (!m_lastColliders.Contains(localid))
3701 {
3702 startedColliders.Add(localid);
3703 }
3704 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
3705 }
3706
3707 // calculate things that ended colliding
3708 foreach (uint localID in m_lastColliders)
3709 {
3710 if (!thisHitColliders.Contains(localID))
3711 {
3712 endedColliders.Add(localID);
3713 }
3714 }
3715 //add the items that started colliding this time to the last colliders list.
3716 foreach (uint localID in startedColliders)
3717 {
3718 m_lastColliders.Add(localID);
3719 }
3720 // remove things that ended colliding from the last colliders list
3721 foreach (uint localID in endedColliders)
3722 {
3723 m_lastColliders.Remove(localID);
3724 }
3725
3726 // do event notification
3727 if (startedColliders.Count > 0)
3728 {
3729 ColliderArgs StartCollidingMessage = new ColliderArgs();
3730 List<DetectedObject> colliding = new List<DetectedObject>();
3731 foreach (uint localId in startedColliders)
3732 {
3733 if (localId == 0)
3734 continue;
3735
3736 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3737 string data = "";
3738 if (obj != null)
3739 {
3740 DetectedObject detobj = new DetectedObject();
3741 detobj.keyUUID = obj.UUID;
3742 detobj.nameStr = obj.Name;
3743 detobj.ownerUUID = obj.OwnerID;
3744 detobj.posVector = obj.AbsolutePosition;
3745 detobj.rotQuat = obj.GetWorldRotation();
3746 detobj.velVector = obj.Velocity;
3747 detobj.colliderType = 0;
3748 detobj.groupUUID = obj.GroupID;
3749 colliding.Add(detobj);
3750 }
3751 }
3752
3753 if (colliding.Count > 0)
3754 {
3755 StartCollidingMessage.Colliders = colliding;
3756
3757 foreach (SceneObjectGroup att in Attachments)
3758 Scene.EventManager.TriggerScriptCollidingStart(att.LocalId, StartCollidingMessage);
3759 }
3760 }
3761
3762 if (endedColliders.Count > 0)
3763 {
3764 ColliderArgs EndCollidingMessage = new ColliderArgs();
3765 List<DetectedObject> colliding = new List<DetectedObject>();
3766 foreach (uint localId in endedColliders)
3767 {
3768 if (localId == 0)
3769 continue;
3770
3771 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3772 string data = "";
3773 if (obj != null)
3774 {
3775 DetectedObject detobj = new DetectedObject();
3776 detobj.keyUUID = obj.UUID;
3777 detobj.nameStr = obj.Name;
3778 detobj.ownerUUID = obj.OwnerID;
3779 detobj.posVector = obj.AbsolutePosition;
3780 detobj.rotQuat = obj.GetWorldRotation();
3781 detobj.velVector = obj.Velocity;
3782 detobj.colliderType = 0;
3783 detobj.groupUUID = obj.GroupID;
3784 colliding.Add(detobj);
3785 }
3786 }
3787
3788 if (colliding.Count > 0)
3789 {
3790 EndCollidingMessage.Colliders = colliding;
3791
3792 foreach (SceneObjectGroup att in Attachments)
3793 Scene.EventManager.TriggerScriptCollidingEnd(att.LocalId, EndCollidingMessage);
3794 }
3795 }
3796
3797 if (thisHitColliders.Count > 0)
3798 {
3799 ColliderArgs CollidingMessage = new ColliderArgs();
3800 List<DetectedObject> colliding = new List<DetectedObject>();
3801 foreach (uint localId in thisHitColliders)
3802 {
3803 if (localId == 0)
3804 continue;
3805
3806 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3807 string data = "";
3808 if (obj != null)
3809 {
3810 DetectedObject detobj = new DetectedObject();
3811 detobj.keyUUID = obj.UUID;
3812 detobj.nameStr = obj.Name;
3813 detobj.ownerUUID = obj.OwnerID;
3814 detobj.posVector = obj.AbsolutePosition;
3815 detobj.rotQuat = obj.GetWorldRotation();
3816 detobj.velVector = obj.Velocity;
3817 detobj.colliderType = 0;
3818 detobj.groupUUID = obj.GroupID;
3819 colliding.Add(detobj);
3820 }
3821 }
3822
3823 if (colliding.Count > 0)
3824 {
3825 CollidingMessage.Colliders = colliding;
3826
3827 lock (m_attachments)
3828 {
3829 foreach (SceneObjectGroup att in m_attachments)
3830 Scene.EventManager.TriggerScriptColliding(att.LocalId, CollidingMessage);
3831 }
3832 }
3833 }
3834
3299 if (m_invulnerable) 3835 if (m_invulnerable)
3300 return; 3836 return;
3301 3837
@@ -3721,6 +4257,39 @@ namespace OpenSim.Region.Framework.Scenes
3721 return; 4257 return;
3722 } 4258 }
3723 4259
4260 XmlDocument doc = new XmlDocument();
4261 string stateData = String.Empty;
4262
4263 IAttachmentsService attServ = m_scene.RequestModuleInterface<IAttachmentsService>();
4264 if (attServ != null)
4265 {
4266 m_log.DebugFormat("[ATTACHMENT]: Loading attachment data from attachment service");
4267 stateData = attServ.Get(ControllingClient.AgentId.ToString());
4268 if (stateData != String.Empty)
4269 {
4270 try
4271 {
4272 doc.LoadXml(stateData);
4273 }
4274 catch { }
4275 }
4276 }
4277
4278 Dictionary<UUID, string> itemData = new Dictionary<UUID, string>();
4279
4280 XmlNodeList nodes = doc.GetElementsByTagName("Attachment");
4281 if (nodes.Count > 0)
4282 {
4283 foreach (XmlNode n in nodes)
4284 {
4285 XmlElement elem = (XmlElement)n;
4286 string itemID = elem.GetAttribute("ItemID");
4287 string xml = elem.InnerXml;
4288
4289 itemData[new UUID(itemID)] = xml;
4290 }
4291 }
4292
3724 List<AvatarAttachment> attachments = m_appearance.GetAttachments(); 4293 List<AvatarAttachment> attachments = m_appearance.GetAttachments();
3725 foreach (AvatarAttachment attach in attachments) 4294 foreach (AvatarAttachment attach in attachments)
3726 { 4295 {
@@ -3741,7 +4310,30 @@ namespace OpenSim.Region.Framework.Scenes
3741 4310
3742 try 4311 try
3743 { 4312 {
3744 m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p); 4313 string xmlData;
4314 XmlDocument d = new XmlDocument();
4315 UUID asset;
4316 if (itemData.TryGetValue(itemID, out xmlData))
4317 {
4318 d.LoadXml(xmlData);
4319 m_log.InfoFormat("[ATTACHMENT]: Found saved state for item {0}, loading it", itemID);
4320
4321 // Rez from inventory
4322 asset
4323 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, d);
4324
4325 }
4326 else
4327 {
4328 // Rez from inventory (with a null doc to let
4329 // CHANGED_OWNER happen)
4330 asset
4331 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, null);
4332 }
4333
4334 m_log.InfoFormat(
4335 "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2}",
4336 p, itemID, asset);
3745 } 4337 }
3746 catch (Exception e) 4338 catch (Exception e)
3747 { 4339 {
@@ -3774,6 +4366,15 @@ namespace OpenSim.Region.Framework.Scenes
3774 m_reprioritization_called = false; 4366 m_reprioritization_called = false;
3775 } 4367 }
3776 } 4368 }
4369
4370 private Vector3 Quat2Euler(Quaternion rot){
4371 float x = Utils.RAD_TO_DEG * (float)Math.Atan2((double)((2.0f * rot.X * rot.W) - (2.0f * rot.Y * rot.Z)) ,
4372 (double)(1 - (2.0f * rot.X * rot.X) - (2.0f * rot.Z * rot.Z)));
4373 float y = Utils.RAD_TO_DEG * (float)Math.Asin ((double)((2.0f * rot.X * rot.Y) + (2.0f * rot.Z * rot.W)));
4374 float z = Utils.RAD_TO_DEG * (float)Math.Atan2(((double)(2.0f * rot.Y * rot.W) - (2.0f * rot.X * rot.Z)) ,
4375 (double)(1 - (2.0f * rot.Y * rot.Y) - (2.0f * rot.Z * rot.Z)));
4376 return(new Vector3(x,y,z));
4377 }
3777 4378
3778 public void SaveChangedAttachments() 4379 public void SaveChangedAttachments()
3779 { 4380 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
index b44a010..40a73a9 100644
--- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
@@ -106,7 +106,7 @@ namespace OpenSim.Region.Framework.Scenes
106 g.ScheduleFullUpdateToAvatar(m_presence); 106 g.ScheduleFullUpdateToAvatar(m_presence);
107 } 107 }
108 108
109 while (m_partsUpdateQueue.Count > 0) 109 while (m_partsUpdateQueue.Count != null && m_partsUpdateQueue.Count > 0)
110 { 110 {
111 SceneObjectPart part = m_partsUpdateQueue.Dequeue(); 111 SceneObjectPart part = m_partsUpdateQueue.Dequeue();
112 112
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 605521a..b2b3ad9 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -102,7 +102,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
102 sceneObject.AddPart(part); 102 sceneObject.AddPart(part);
103 part.LinkNum = linkNum; 103 part.LinkNum = linkNum;
104 part.TrimPermissions(); 104 part.TrimPermissions();
105 part.StoreUndoState(); 105 part.StoreUndoState(UndoType.STATE_ALL);
106 reader.Close(); 106 reader.Close();
107 sr.Close(); 107 sr.Close();
108 } 108 }
@@ -220,7 +220,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
220 if (originalLinkNum != 0) 220 if (originalLinkNum != 0)
221 part.LinkNum = originalLinkNum; 221 part.LinkNum = originalLinkNum;
222 222
223 part.StoreUndoState(); 223 part.StoreUndoState(UndoType.STATE_ALL);
224 reader.Close(); 224 reader.Close();
225 sr.Close(); 225 sr.Close();
226 } 226 }
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
index 55e407e..f71b507 100644
--- a/OpenSim/Region/Framework/Scenes/UndoState.cs
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -27,48 +27,125 @@
27 27
28using OpenMetaverse; 28using OpenMetaverse;
29using OpenSim.Region.Framework.Interfaces; 29using OpenSim.Region.Framework.Interfaces;
30using System;
30 31
31namespace OpenSim.Region.Framework.Scenes 32namespace OpenSim.Region.Framework.Scenes
32{ 33{
34 [Flags]
35 public enum UndoType
36 {
37 STATE_PRIM_POSITION = 1,
38 STATE_PRIM_ROTATION = 2,
39 STATE_PRIM_SCALE = 4,
40 STATE_PRIM_ALL = 7,
41 STATE_GROUP_POSITION = 8,
42 STATE_GROUP_ROTATION = 16,
43 STATE_GROUP_SCALE = 32,
44 STATE_GROUP_ALL = 56,
45 STATE_ALL = 63
46 }
47
33 public class UndoState 48 public class UndoState
34 { 49 {
35 public Vector3 Position = Vector3.Zero; 50 public Vector3 Position = Vector3.Zero;
36 public Vector3 Scale = Vector3.Zero; 51 public Vector3 Scale = Vector3.Zero;
37 public Quaternion Rotation = Quaternion.Identity; 52 public Quaternion Rotation = Quaternion.Identity;
53 public Vector3 GroupPosition = Vector3.Zero;
54 public Quaternion GroupRotation = Quaternion.Identity;
55 public Vector3 GroupScale = Vector3.Zero;
56 public DateTime LastUpdated = DateTime.Now;
57 public UndoType Type;
38 58
39 public UndoState(SceneObjectPart part) 59 public UndoState(SceneObjectPart part, UndoType type)
40 { 60 {
61 Type = type;
41 if (part != null) 62 if (part != null)
42 { 63 {
43 if (part.ParentID == 0) 64 if (part.ParentID == 0)
44 { 65 {
45 Position = part.ParentGroup.AbsolutePosition; 66 GroupScale = part.ParentGroup.RootPart.Shape.Scale;
67
68 //FUBAR WARNING: Do NOT get the group's absoluteposition here
69 //or you'll experience a loop and/or a stack issue
70 GroupPosition = part.ParentGroup.RootPart.AbsolutePosition;
71 GroupRotation = part.ParentGroup.GroupRotation;
72 Position = part.ParentGroup.RootPart.AbsolutePosition;
46 Rotation = part.RotationOffset; 73 Rotation = part.RotationOffset;
47 Scale = part.Shape.Scale; 74 Scale = part.Shape.Scale;
75 LastUpdated = DateTime.Now;
48 } 76 }
49 else 77 else
50 { 78 {
79 GroupScale = part.Shape.Scale;
80
81 //FUBAR WARNING: Do NOT get the group's absoluteposition here
82 //or you'll experience a loop and/or a stack issue
83 GroupPosition = part.ParentGroup.RootPart.AbsolutePosition;
84 GroupRotation = part.ParentGroup.Rotation;
51 Position = part.OffsetPosition; 85 Position = part.OffsetPosition;
52 Rotation = part.RotationOffset; 86 Rotation = part.RotationOffset;
53 Scale = part.Shape.Scale; 87 Scale = part.Shape.Scale;
88 LastUpdated = DateTime.Now;
54 } 89 }
55 } 90 }
56 } 91 }
57 92 public void Merge(UndoState last)
93 {
94 if ((Type & UndoType.STATE_GROUP_POSITION) == 0 || ((last.Type & UndoType.STATE_GROUP_POSITION) >= (Type & UndoType.STATE_GROUP_POSITION)))
95 {
96 GroupPosition = last.GroupPosition;
97 Position = last.Position;
98 }
99 if ((Type & UndoType.STATE_GROUP_SCALE) == 0 || ((last.Type & UndoType.STATE_GROUP_SCALE) >= (Type & UndoType.STATE_GROUP_SCALE)))
100 {
101 GroupScale = last.GroupScale;
102 Scale = last.Scale;
103 }
104 if ((Type & UndoType.STATE_GROUP_ROTATION) == 0 || ((last.Type & UndoType.STATE_GROUP_ROTATION) >= (Type & UndoType.STATE_GROUP_ROTATION)))
105 {
106 GroupRotation = last.GroupRotation;
107 Rotation = last.Rotation;
108 }
109 if ((Type & UndoType.STATE_PRIM_POSITION) == 0 || ((last.Type & UndoType.STATE_PRIM_POSITION) >= (Type & UndoType.STATE_PRIM_POSITION)))
110 {
111 Position = last.Position;
112 }
113 if ((Type & UndoType.STATE_PRIM_SCALE) == 0 || ((last.Type & UndoType.STATE_PRIM_SCALE) >= (Type & UndoType.STATE_PRIM_SCALE)))
114 {
115 Scale = last.Scale;
116 }
117 if ((Type & UndoType.STATE_PRIM_ROTATION) == 0 || ((last.Type & UndoType.STATE_PRIM_ROTATION) >= (Type & UndoType.STATE_PRIM_ROTATION)))
118 {
119 Rotation = last.Rotation;
120 }
121 Type = Type | last.Type;
122 }
123 public bool Compare(UndoState undo)
124 {
125 if (undo == null || Position == null) return false;
126 if (undo.Position == Position && undo.Rotation == Rotation && undo.Scale == Scale && undo.GroupPosition == GroupPosition && undo.GroupScale == GroupScale && undo.GroupRotation == GroupRotation)
127 {
128 return true;
129 }
130 else
131 {
132 return false;
133 }
134 }
58 public bool Compare(SceneObjectPart part) 135 public bool Compare(SceneObjectPart part)
59 { 136 {
60 if (part != null) 137 if (part != null)
61 { 138 {
62 if (part.ParentID == 0) 139 if (part.ParentID == 0)
63 { 140 {
64 if (Position == part.ParentGroup.AbsolutePosition && Rotation == part.ParentGroup.Rotation) 141 if (Position == part.ParentGroup.RootPart.AbsolutePosition && Rotation == part.ParentGroup.Rotation && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale)
65 return true; 142 return true;
66 else 143 else
67 return false; 144 return false;
68 } 145 }
69 else 146 else
70 { 147 {
71 if (Position == part.OffsetPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale) 148 if (Position == part.OffsetPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale)
72 return true; 149 return true;
73 else 150 else
74 return false; 151 return false;
@@ -78,62 +155,70 @@ namespace OpenSim.Region.Framework.Scenes
78 return false; 155 return false;
79 } 156 }
80 157
81 public void PlaybackState(SceneObjectPart part) 158 private void RestoreState(SceneObjectPart part)
82 { 159 {
160 bool GroupChange = false;
161 if ((Type & UndoType.STATE_GROUP_POSITION) != 0
162 || (Type & UndoType.STATE_GROUP_ROTATION) != 0
163 || (Type & UndoType.STATE_GROUP_SCALE) != 0)
164 {
165 GroupChange = true;
166 }
167
83 if (part != null) 168 if (part != null)
84 { 169 {
85 part.Undoing = true; 170 part.Undoing = true;
86 171
87 if (part.ParentID == 0) 172 if (part.ParentID == 0 && GroupChange == false)
88 { 173 {
89 if (Position != Vector3.Zero) 174 if (Position != Vector3.Zero)
90 part.ParentGroup.AbsolutePosition = Position; 175
91 part.RotationOffset = Rotation; 176 part.ParentGroup.UpdateSinglePosition(Position, part.LocalId);
177 part.ParentGroup.UpdateSingleRotation(Rotation, part.LocalId);
92 if (Scale != Vector3.Zero) 178 if (Scale != Vector3.Zero)
93 part.Resize(Scale); 179 part.Resize(Scale);
94 part.ParentGroup.ScheduleGroupForTerseUpdate(); 180 part.ParentGroup.ScheduleGroupForTerseUpdate();
95 } 181 }
96 else 182 else
97 { 183 {
98 if (Position != Vector3.Zero) 184 if (GroupChange)
99 part.OffsetPosition = Position; 185 {
100 part.UpdateRotation(Rotation); 186 part.ParentGroup.RootPart.Undoing = true;
101 if (Scale != Vector3.Zero) 187 if (GroupPosition != Vector3.Zero)
102 part.Resize(Scale); part.ScheduleTerseUpdate(); 188 {
189 //Calculate the scale...
190 Vector3 gs = part.Shape.Scale;
191 float scale = GroupScale.Z / gs.Z;
192
193 //Scale first since it can affect our position
194 part.ParentGroup.GroupResize(gs * scale, part.LocalId);
195 part.ParentGroup.AbsolutePosition = GroupPosition;
196 part.ParentGroup.UpdateGroupRotationR(GroupRotation);
197
198 }
199 part.ParentGroup.RootPart.Undoing = false;
200 }
201 else
202 {
203 if (Position != Vector3.Zero) //We can use this for all the updates since all are set
204 {
205 part.OffsetPosition = Position;
206 part.UpdateRotation(Rotation);
207 part.Resize(Scale); part.ScheduleTerseUpdate();
208 }
209 }
103 } 210 }
104 part.Undoing = false; 211 part.Undoing = false;
105 212
106 } 213 }
107 } 214 }
215 public void PlaybackState(SceneObjectPart part)
216 {
217 RestoreState(part);
218 }
108 public void PlayfwdState(SceneObjectPart part) 219 public void PlayfwdState(SceneObjectPart part)
109 { 220 {
110 if (part != null) 221 RestoreState(part);
111 {
112 part.Undoing = true;
113
114 if (part.ParentID == 0)
115 {
116 if (Position != Vector3.Zero)
117 part.ParentGroup.AbsolutePosition = Position;
118 if (Rotation != Quaternion.Identity)
119 part.UpdateRotation(Rotation);
120 if (Scale != Vector3.Zero)
121 part.Resize(Scale);
122 part.ParentGroup.ScheduleGroupForTerseUpdate();
123 }
124 else
125 {
126 if (Position != Vector3.Zero)
127 part.OffsetPosition = Position;
128 if (Rotation != Quaternion.Identity)
129 part.UpdateRotation(Rotation);
130 if (Scale != Vector3.Zero)
131 part.Resize(Scale);
132 part.ScheduleTerseUpdate();
133 }
134 part.Undoing = false;
135
136 }
137 } 222 }
138 } 223 }
139 public class LandUndoState 224 public class LandUndoState
@@ -161,3 +246,4 @@ namespace OpenSim.Region.Framework.Scenes
161 } 246 }
162 } 247 }
163} 248}
249
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 49382f0..e2574e7 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -813,6 +813,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
813 public event ObjectOwner OnObjectOwner; 813 public event ObjectOwner OnObjectOwner;
814 public event DirPlacesQuery OnDirPlacesQuery; 814 public event DirPlacesQuery OnDirPlacesQuery;
815 public event DirFindQuery OnDirFindQuery; 815 public event DirFindQuery OnDirFindQuery;
816 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
816 public event DirLandQuery OnDirLandQuery; 817 public event DirLandQuery OnDirLandQuery;
817 public event DirPopularQuery OnDirPopularQuery; 818 public event DirPopularQuery OnDirPopularQuery;
818 public event DirClassifiedQuery OnDirClassifiedQuery; 819 public event DirClassifiedQuery OnDirClassifiedQuery;
@@ -883,6 +884,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
883 884
884 public void Close() 885 public void Close()
885 { 886 {
887 Close(true);
888 }
889
890 public void Close(bool sendStop)
891 {
886 Disconnect(); 892 Disconnect();
887 } 893 }
888 894
@@ -937,7 +943,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
937 943
938 } 944 }
939 945
940 public void SendKillObject(ulong regionHandle, uint localID) 946 public void SendKillObject(ulong regionHandle, List<uint> localID)
941 { 947 {
942 948
943 } 949 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index e9c5453..d75e25d 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -564,7 +564,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
564 564
565 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request) 565 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request)
566 { 566 {
567 m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called"); 567// m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called");
568 568
569 Hashtable response = new Hashtable(); 569 Hashtable response = new Hashtable();
570 response["content_type"] = "text/xml"; 570 response["content_type"] = "text/xml";
@@ -670,7 +670,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
670 670
671 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request) 671 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request)
672 { 672 {
673 m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called"); 673// m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called");
674 string requestbody = (string)request["body"]; 674 string requestbody = (string)request["body"];
675 string uri = (string)request["uri"]; 675 string uri = (string)request["uri"];
676 string contenttype = (string)request["content-type"]; 676 string contenttype = (string)request["content-type"];
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
index 3a6996e..84c7f29 100644
--- a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
@@ -259,9 +259,10 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
259 // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles. 259 // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles.
260 ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup(); 260 ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup();
261 scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor); 261 scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor);
262 scene.SendKillObject(scene.Entities[uuid].LocalId); 262 scene.SendKillObject(new List<uint>() { scene.Entities[uuid].LocalId });
263 scene.SceneGraph.DeleteSceneObject(uuid, false); 263 scene.SceneGraph.DeleteSceneObject(uuid, false);
264 ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroupFromScene(false); 264 ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroupFromScene(false);
265 scene.SendKillObject(new List<uint>() { ((SceneObjectGroup)scene.Entities[uuid]).LocalId });
265 } 266 }
266 catch(Exception e) 267 catch(Exception e)
267 { 268 {
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
index c7b1ed7..cd60f4b 100644
--- a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
@@ -175,7 +175,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
175 //This is important because we are not IN any database. 175 //This is important because we are not IN any database.
176 //m_Entity.FakeDeleteGroup(); 176 //m_Entity.FakeDeleteGroup();
177 foreach (SceneObjectPart part in m_Entity.Parts) 177 foreach (SceneObjectPart part in m_Entity.Parts)
178 client.SendKillObject(m_Entity.RegionHandle, part.LocalId); 178 client.SendKillObject(m_Entity.RegionHandle, new List<uint>() { part.LocalId });
179 } 179 }
180 180
181 /// <summary> 181 /// <summary>
@@ -187,7 +187,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
187 { 187 {
188 m_Entity.Scene.ForEachClient( 188 m_Entity.Scene.ForEachClient(
189 delegate(IClientAPI controller) 189 delegate(IClientAPI controller)
190 { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); } 190 { controller.SendKillObject(m_Entity.RegionHandle, new List<uint>() { part.LocalId }); }
191 ); 191 );
192 } 192 }
193 } 193 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
index 32659c8..11c87f8 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
@@ -42,17 +42,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
42 public class XmlRpcRouter : IRegionModule, IXmlRpcRouter 42 public class XmlRpcRouter : IRegionModule, IXmlRpcRouter
43 { 43 {
44 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 45 private bool m_enabled = false;
46 public void Initialise(Scene scene, IConfigSource config) 46 public void Initialise(Scene scene, IConfigSource config)
47 { 47 {
48 IConfig startupConfig = config.Configs["Startup"]; 48 IConfig startupConfig = config.Configs["XMLRPC"];
49 if (startupConfig == null) 49 if (startupConfig == null)
50 return; 50 return;
51 51
52 if (startupConfig.GetString("XmlRpcRouterModule", 52 if (startupConfig.GetString("XmlRpcRouterModule",
53 "XmlRpcRouterModule") == "XmlRpcRouterModule") 53 "") == "XmlRpcRouterModule")
54 { 54 {
55 scene.RegisterModuleInterface<IXmlRpcRouter>(this); 55 scene.RegisterModuleInterface<IXmlRpcRouter>(this);
56 m_enabled = true;
57 }
58 else
59 {
60 m_enabled = false;
56 } 61 }
57 } 62 }
58 63
@@ -76,7 +81,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
76 81
77 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) 82 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri)
78 { 83 {
79 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri}); 84 if (m_enabled)
85 {
86 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] { uri });
87 }
80 } 88 }
81 89
82 public void ScriptRemoved(UUID itemID) 90 public void ScriptRemoved(UUID itemID)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 5d44aa1..1ce3791 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -156,7 +156,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
156#pragma warning disable 67 156#pragma warning disable 67
157 public event Action<IClientAPI> OnLogout; 157 public event Action<IClientAPI> OnLogout;
158 public event ObjectPermissions OnObjectPermissions; 158 public event ObjectPermissions OnObjectPermissions;
159 159 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
160 public event MoneyTransferRequest OnMoneyTransferRequest; 160 public event MoneyTransferRequest OnMoneyTransferRequest;
161 public event ParcelBuy OnParcelBuy; 161 public event ParcelBuy OnParcelBuy;
162 public event Action<IClientAPI> OnConnectionClosed; 162 public event Action<IClientAPI> OnConnectionClosed;
@@ -519,7 +519,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
519 519
520 } 520 }
521 521
522 public virtual void SendKillObject(ulong regionHandle, uint localID) 522 public virtual void SendKillObject(ulong regionHandle, List<uint> localID)
523 { 523 {
524 } 524 }
525 525
@@ -846,6 +846,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
846 846
847 public void Close() 847 public void Close()
848 { 848 {
849 Close(true);
850 }
851
852 public void Close(bool sendStop)
853 {
849 } 854 }
850 855
851 public void Start() 856 public void Start()
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index 421da36..2563361 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -386,7 +386,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
386 m_scene.ForEachClient(delegate(IClientAPI controller) 386 m_scene.ForEachClient(delegate(IClientAPI controller)
387 { 387 {
388 controller.SendKillObject(m_scene.RegionInfo.RegionHandle, 388 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
389 selectedTree.LocalId); 389 new List<uint>() { selectedTree.LocalId });
390 }); 390 });
391 } 391 }
392 else 392 else
@@ -727,7 +727,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
727 m_scene.ForEachClient(delegate(IClientAPI controller) 727 m_scene.ForEachClient(delegate(IClientAPI controller)
728 { 728 {
729 controller.SendKillObject(m_scene.RegionInfo.RegionHandle, 729 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
730 selectedTree.LocalId); 730 new List<uint>() { selectedTree.LocalId });
731 }); 731 });
732 732
733 break; 733 break;
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
index ac4e2b9..f13c323 100644
--- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
+++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
@@ -624,8 +624,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
624 { 624 {
625 set { return; } 625 set { return; }
626 } 626 }
627 627
628
629 public override Quaternion APIDTarget 628 public override Quaternion APIDTarget
630 { 629 {
631 set { return; } 630 set { return; }
diff --git a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
index e2a6a2e..f4245b6 100644
--- a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
+++ b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
@@ -996,7 +996,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
996 { 996 {
997 997
998 } 998 }
999 999
1000 public override void VehicleFlags(int param, bool remove) 1000 public override void VehicleFlags(int param, bool remove)
1001 { 1001 {
1002 1002
diff --git a/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
new file mode 100644
index 0000000..d65929a
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("OdePlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("OdePlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.6.5.*")]
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
new file mode 100644
index 0000000..93f9964
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
@@ -0,0 +1,1437 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using Ode.NET;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using log4net;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 /// <summary>
40 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
41 /// </summary>
42
43 public enum dParam : int
44 {
45 LowStop = 0,
46 HiStop = 1,
47 Vel = 2,
48 FMax = 3,
49 FudgeFactor = 4,
50 Bounce = 5,
51 CFM = 6,
52 StopERP = 7,
53 StopCFM = 8,
54 LoStop2 = 256,
55 HiStop2 = 257,
56 Vel2 = 258,
57 FMax2 = 259,
58 StopERP2 = 7 + 256,
59 StopCFM2 = 8 + 256,
60 LoStop3 = 512,
61 HiStop3 = 513,
62 Vel3 = 514,
63 FMax3 = 515,
64 StopERP3 = 7 + 512,
65 StopCFM3 = 8 + 512
66 }
67 public class OdeCharacter : PhysicsActor
68 {
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Vector3 _position;
72 private d.Vector3 _zeroPosition;
73 // private d.Matrix3 m_StandUpRotation;
74 private bool _zeroFlag = false;
75 private bool m_lastUpdateSent = false;
76 private Vector3 _velocity;
77 private Vector3 _target_velocity;
78 private Vector3 _acceleration;
79 private Vector3 m_rotationalVelocity;
80 private float m_mass = 80f;
81 public float m_density = 60f;
82 private bool m_pidControllerActive = true;
83 public float PID_D = 800.0f;
84 public float PID_P = 900.0f;
85 //private static float POSTURE_SERVO = 10000.0f;
86 public float CAPSULE_RADIUS = 0.37f;
87 public float CAPSULE_LENGTH = 2.140599f;
88 public float m_tensor = 3800000f;
89 public float heightFudgeFactor = 0.52f;
90 public float walkDivisor = 1.3f;
91 public float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool jumping = false; // add for jumping
94 private bool m_iscolliding = false;
95 private bool m_iscollidingGround = false;
96 private bool m_wascolliding = false;
97 private bool m_wascollidingGround = false;
98 private bool m_iscollidingObj = false;
99 private bool m_alwaysRun = false;
100 private bool m_hackSentFall = false;
101 private bool m_hackSentFly = false;
102 private int m_requestedUpdateFrequency = 0;
103 private Vector3 m_taintPosition = Vector3.Zero;
104 public uint m_localID = 0;
105 public bool m_returnCollisions = false;
106 // taints and their non-tainted counterparts
107 public bool m_isPhysical = false; // the current physical status
108 public bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
109 public float MinimumGroundFlightOffset = 3f;
110
111 private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
112 private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; // used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
113
114
115 private float m_buoyancy = 0f;
116
117 // private CollisionLocker ode;
118
119 private string m_name = String.Empty;
120
121 private bool[] m_colliderarr = new bool[11];
122 private bool[] m_colliderGroundarr = new bool[11];
123
124 // Default we're a Character
125 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
126
127 // Default, Collide with Other Geometries, spaces, bodies and characters.
128 private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
129 | CollisionCategories.Space
130 | CollisionCategories.Body
131 | CollisionCategories.Character
132 | CollisionCategories.Land);
133 public IntPtr Body = IntPtr.Zero;
134 private OdeScene _parent_scene;
135 public IntPtr Shell = IntPtr.Zero;
136 public IntPtr Amotor = IntPtr.Zero;
137 public d.Mass ShellMass;
138 public bool collidelock = false;
139
140 public int m_eventsubscription = 0;
141 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
142
143 // unique UUID of this character object
144 public UUID m_uuid;
145 public bool bad = false;
146 private Object m_syncRoot = new Object();
147
148 public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, CollisionLocker dode, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor)
149 {
150 m_uuid = UUID.Random();
151
152 if (pos.IsFinite())
153 {
154 if (pos.Z > 9999999f)
155 {
156 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
157 }
158 if (pos.Z < -90000f)
159 {
160 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
161 }
162 _position = pos;
163 m_taintPosition.X = pos.X;
164 m_taintPosition.Y = pos.Y;
165 m_taintPosition.Z = pos.Z;
166 }
167 else
168 {
169 _position = new Vector3(((float)_parent_scene.WorldExtents.X * 0.5f), ((float)_parent_scene.WorldExtents.Y * 0.5f), parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
170 m_taintPosition.X = _position.X;
171 m_taintPosition.Y = _position.Y;
172 m_taintPosition.Z = _position.Z;
173 m_log.Warn("[PHYSICS]: Got NaN Position on Character Create");
174 }
175
176 _parent_scene = parent_scene;
177
178 PID_D = pid_d;
179 PID_P = pid_p;
180 CAPSULE_RADIUS = capsule_radius;
181 m_tensor = tensor;
182 m_density = density;
183 heightFudgeFactor = height_fudge_factor;
184 walkDivisor = walk_divisor;
185 runDivisor = rundivisor;
186
187 // m_StandUpRotation =
188 // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
189 // 0.5f);
190
191 for (int i = 0; i < 11; i++)
192 {
193 m_colliderarr[i] = false;
194 }
195 CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f;
196 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
197 m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH;
198
199 m_isPhysical = false; // current status: no ODE information exists
200 m_tainted_isPhysical = true; // new tainted status: need to create ODE information
201
202 _parent_scene.AddPhysicsActorTaint(this);
203
204 m_name = avName;
205 }
206
207 public override int PhysicsActorType
208 {
209 get { return (int) ActorTypes.Agent; }
210 set { return; }
211 }
212
213 /// <summary>
214 /// If this is set, the avatar will move faster
215 /// </summary>
216 public override bool SetAlwaysRun
217 {
218 get { return m_alwaysRun; }
219 set { m_alwaysRun = value; }
220 }
221
222 public override uint LocalID
223 {
224 set { m_localID = value; }
225 }
226
227 public override bool Grabbed
228 {
229 set { return; }
230 }
231
232 public override bool Selected
233 {
234// set { return; }
235 set { jumping = value; } // add for jumping flag
236 }
237
238 public override float Buoyancy
239 {
240 get { return m_buoyancy; }
241 set { m_buoyancy = value; }
242 }
243
244 public override bool FloatOnWater
245 {
246 set { return; }
247 }
248
249 public override bool IsPhysical
250 {
251 get { return false; }
252 set { return; }
253 }
254
255 public override bool ThrottleUpdates
256 {
257 get { return false; }
258 set { return; }
259 }
260
261 public override bool Flying
262 {
263 get { return flying; }
264 set { flying = value; }
265 }
266
267 /// <summary>
268 /// Returns if the avatar is colliding in general.
269 /// This includes the ground and objects and avatar.
270 /// </summary>
271 public override bool IsColliding
272 {
273//#@ get { return m_iscolliding; }
274 get { //##
275//Console.WriteLine(">>>>>>>>>>>> IC get = {0}", m_iscolliding); //##
276 return m_iscolliding; } //##
277 set
278 {
279 int i;
280 int truecount = 0;
281 int falsecount = 0;
282
283 if (m_colliderarr.Length >= 10)
284 {
285 for (i = 0; i < 10; i++)
286 {
287 m_colliderarr[i] = m_colliderarr[i + 1];
288 }
289 }
290 m_colliderarr[10] = value;
291
292 for (i = 0; i < 11; i++)
293 {
294 if (m_colliderarr[i])
295 {
296 truecount++;
297 }
298 else
299 {
300 falsecount++;
301 }
302 }
303
304 // Equal truecounts and false counts means we're colliding with something.
305
306 if (falsecount > 1.2*truecount)
307 {
308 m_iscolliding = false;
309 }
310 else
311 {
312 m_iscolliding = true;
313 }
314// ## Console.WriteLine("IC SET = {0} t{1} f{2} i {3}", value, truecount, falsecount, m_iscolliding);
315 if (m_wascolliding != m_iscolliding)
316 {
317 //base.SendCollisionUpdate(new CollisionEventUpdate());
318 }
319 m_wascolliding = m_iscolliding;
320 }
321 }
322
323 /// <summary>
324 /// Returns if an avatar is colliding with the ground
325 /// </summary>
326 public override bool CollidingGround
327 {
328 get { return m_iscollidingGround; }
329 set
330 {
331 // Collisions against the ground are not really reliable
332 // So, to get a consistant value we have to average the current result over time
333 // Currently we use 1 second = 10 calls to this.
334 int i;
335 int truecount = 0;
336 int falsecount = 0;
337
338 if (m_colliderGroundarr.Length >= 10)
339 {
340 for (i = 0; i < 10; i++)
341 {
342 m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
343 }
344 }
345 m_colliderGroundarr[10] = value;
346
347 for (i = 0; i < 11; i++)
348 {
349 if (m_colliderGroundarr[i])
350 {
351 truecount++;
352 }
353 else
354 {
355 falsecount++;
356 }
357 }
358
359 // Equal truecounts and false counts means we're colliding with something.
360
361 if (falsecount > 1.2*truecount)
362 {
363 m_iscollidingGround = false;
364 }
365 else
366 {
367 m_iscollidingGround = true;
368 }
369 if (m_wascollidingGround != m_iscollidingGround)
370 {
371 //base.SendCollisionUpdate(new CollisionEventUpdate());
372 }
373 m_wascollidingGround = m_iscollidingGround;
374 }
375 }
376
377 /// <summary>
378 /// Returns if the avatar is colliding with an object
379 /// </summary>
380 public override bool CollidingObj
381 {
382 get { return m_iscollidingObj; }
383 set
384 {
385 m_iscollidingObj = value;
386 if (value)
387 m_pidControllerActive = false;
388 else
389 m_pidControllerActive = true;
390 }
391 }
392
393 /// <summary>
394 /// turn the PID controller on or off.
395 /// The PID Controller will turn on all by itself in many situations
396 /// </summary>
397 /// <param name="status"></param>
398 public void SetPidStatus(bool status)
399 {
400 m_pidControllerActive = status;
401 }
402
403 public override bool Stopped
404 {
405 get { return _zeroFlag; }
406 }
407
408 /// <summary>
409 /// This 'puts' an avatar somewhere in the physics space.
410 /// Not really a good choice unless you 'know' it's a good
411 /// spot otherwise you're likely to orbit the avatar.
412 /// </summary>
413 public override Vector3 Position
414 {
415 get { return _position; }
416 set
417 {
418 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
419 {
420 if (value.IsFinite())
421 {
422 if (value.Z > 9999999f)
423 {
424 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
425 }
426 if (value.Z < -90000f)
427 {
428 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
429 }
430
431 _position.X = value.X;
432 _position.Y = value.Y;
433 _position.Z = value.Z;
434
435 m_taintPosition.X = value.X;
436 m_taintPosition.Y = value.Y;
437 m_taintPosition.Z = value.Z;
438 _parent_scene.AddPhysicsActorTaint(this);
439 }
440 else
441 {
442 m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character");
443 }
444 }
445 }
446 }
447
448 public override Vector3 RotationalVelocity
449 {
450 get { return m_rotationalVelocity; }
451 set { m_rotationalVelocity = value; }
452 }
453
454 /// <summary>
455 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
456 /// and use it to offset landings properly
457 /// </summary>
458 public override Vector3 Size
459 {
460 get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
461 set
462 {
463 if (value.IsFinite())
464 {
465 m_pidControllerActive = true;
466
467 Vector3 SetSize = value;
468 m_tainted_CAPSULE_LENGTH = (SetSize.Z*1.15f) - CAPSULE_RADIUS*2.0f;
469 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
470
471 Velocity = Vector3.Zero;
472 m_taintPosition = _position; // update the stale taint position
473 _parent_scene.AddPhysicsActorTaint(this);
474 }
475 else
476 {
477 m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character");
478 }
479 }
480 }
481
482 private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
483 {
484 movementVector.Z = 0f;
485 float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
486 if (magnitude < 0.1f) return;
487
488 // normalize the velocity vector
489 float invMagnitude = 1.0f / magnitude;
490 movementVector.X *= invMagnitude;
491 movementVector.Y *= invMagnitude;
492
493 // if we change the capsule heading too often, the capsule can fall down
494 // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
495 // meaning only 4 possible capsule tilt orientations
496 if (movementVector.X > 0)
497 {
498 // east
499 if (movementVector.Y > 0)
500 {
501 // northeast
502 movementVector.X = (float)Math.Sqrt(2.0);
503 movementVector.Y = (float)Math.Sqrt(2.0);
504 }
505 else
506 {
507 // southeast
508 movementVector.X = (float)Math.Sqrt(2.0);
509 movementVector.Y = -(float)Math.Sqrt(2.0);
510 }
511 }
512 else
513 {
514 // west
515 if (movementVector.Y > 0)
516 {
517 // northwest
518 movementVector.X = -(float)Math.Sqrt(2.0);
519 movementVector.Y = (float)Math.Sqrt(2.0);
520 }
521 else
522 {
523 // southwest
524 movementVector.X = -(float)Math.Sqrt(2.0);
525 movementVector.Y = -(float)Math.Sqrt(2.0);
526 }
527 }
528
529
530 // movementVector.Z is zero
531
532 // calculate tilt components based on desired amount of tilt and current (snapped) heading.
533 // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
534 float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
535 float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
536
537 //m_log.Debug("[PHYSICS] changing avatar tilt");
538 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
539 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
540 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
541 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
542 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
543 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
544 }
545
546 /// <summary>
547 /// This creates the Avatar's physical Surrogate at the position supplied
548 /// </summary>
549 /// <param name="npositionX"></param>
550 /// <param name="npositionY"></param>
551 /// <param name="npositionZ"></param>
552
553 // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
554 // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
555 // place that is safe to call this routine AvatarGeomAndBodyCreation.
556 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor)
557 {
558 //CAPSULE_LENGTH = -5;
559 //CAPSULE_RADIUS = -5;
560 int dAMotorEuler = 1;
561 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
562 if (CAPSULE_LENGTH <= 0)
563 {
564 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
565 CAPSULE_LENGTH = 0.01f;
566
567 }
568
569 if (CAPSULE_RADIUS <= 0)
570 {
571 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
572 CAPSULE_RADIUS = 0.01f;
573
574 }
575
576 if(Shell != IntPtr.Zero)
577 {
578 try
579 {
580 d.GeomDestroy(Shell);
581 }
582 catch (System.AccessViolationException)
583 {
584 m_log.Error("[PHYSICS]: PrimGeom dead");
585 }
586 // Remove any old entries
587//string tShell;
588//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
589//Console.WriteLine("**** Remove {0}", tShell);
590 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
591 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
592 }
593
594 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
595 _parent_scene.geom_name_map[Shell] = m_name;
596 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this;
597Console.WriteLine("**** Create {2} Dicts: actor={0} name={1} height={3} rad={4}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, m_name, CAPSULE_LENGTH, CAPSULE_RADIUS);
598
599 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
600 d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
601
602 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
603 Body = d.BodyCreate(_parent_scene.world);
604 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
605
606 _position.X = npositionX;
607 _position.Y = npositionY;
608 _position.Z = npositionZ;
609
610
611 m_taintPosition.X = npositionX;
612 m_taintPosition.Y = npositionY;
613 m_taintPosition.Z = npositionZ;
614
615 d.BodySetMass(Body, ref ShellMass);
616 d.Matrix3 m_caprot;
617 // 90 Stand up on the cap of the capped cyllinder
618 if (_parent_scene.IsAvCapsuleTilted)
619 {
620 d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
621 }
622 else
623 {
624 d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
625 }
626
627
628 d.GeomSetRotation(Shell, ref m_caprot);
629 d.BodySetRotation(Body, ref m_caprot);
630
631 d.GeomSetBody(Shell, Body);
632
633
634 // The purpose of the AMotor here is to keep the avatar's physical
635 // surrogate from rotating while moving
636 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
637 d.JointAttach(Amotor, Body, IntPtr.Zero);
638 d.JointSetAMotorMode(Amotor, dAMotorEuler);
639 d.JointSetAMotorNumAxes(Amotor, 3);
640 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
641 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
642 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
643 d.JointSetAMotorAngle(Amotor, 0, 0);
644 d.JointSetAMotorAngle(Amotor, 1, 0);
645 d.JointSetAMotorAngle(Amotor, 2, 0);
646
647 // These lowstops and high stops are effectively (no wiggle room)
648 if (_parent_scene.IsAvCapsuleTilted)
649 {
650 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
651 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
652 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
653 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
654 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
655 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
656 }
657 else
658 {
659 #region Documentation of capsule motor LowStop and HighStop parameters
660 // Intentionally introduce some tilt into the capsule by setting
661 // the motor stops to small epsilon values. This small tilt prevents
662 // the capsule from falling into the terrain; a straight-up capsule
663 // (with -0..0 motor stops) falls into the terrain for reasons yet
664 // to be comprehended in their entirety.
665 #endregion
666 AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
667 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
668 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
669 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
670 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
671 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
672 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
673 }
674
675 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
676 // capped cyllinder will fall over
677 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
678 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
679
680 //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
681 //d.QfromR(
682 //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
683 //
684 //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
685 //standupStraight();
686 }
687
688 //
689 /// <summary>
690 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
691 /// This may be used in calculations in the scene/scenepresence
692 /// </summary>
693 public override float Mass
694 {
695 get
696 {
697 float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH);
698 return m_density*AVvolume;
699 }
700 }
701 public override void link(PhysicsActor obj)
702 {
703
704 }
705
706 public override void delink()
707 {
708
709 }
710
711 public override void LockAngularMotion(Vector3 axis)
712 {
713
714 }
715
716// This code is very useful. Written by DanX0r. We're just not using it right now.
717// Commented out to prevent a warning.
718//
719// private void standupStraight()
720// {
721// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
722// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
723// // change appearance and when you enter the simulator
724// // After this routine is done, the amotor stabilizes much quicker
725// d.Vector3 feet;
726// d.Vector3 head;
727// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
728// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
729// float posture = head.Z - feet.Z;
730
731// // restoring force proportional to lack of posture:
732// float servo = (2.5f - posture) * POSTURE_SERVO;
733// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
734// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
735// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
736// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
737// }
738
739 public override Vector3 Force
740 {
741 get { return _target_velocity; }
742 set { return; }
743 }
744
745 public override int VehicleType
746 {
747 get { return 0; }
748 set { return; }
749 }
750
751 public override void VehicleFloatParam(int param, float value)
752 {
753
754 }
755
756 public override void VehicleVectorParam(int param, Vector3 value)
757 {
758
759 }
760
761 public override void VehicleRotationParam(int param, Quaternion rotation)
762 {
763
764 }
765
766 public override void VehicleFlags(int flags, bool remove)
767 {
768 }
769
770 public override void SetVolumeDetect(int param)
771 {
772
773 }
774
775 public override Vector3 CenterOfMass
776 {
777 get { return Vector3.Zero; }
778 }
779
780 public override Vector3 GeometricCenter
781 {
782 get { return Vector3.Zero; }
783 }
784
785 public override PrimitiveBaseShape Shape
786 {
787 set { return; }
788 }
789
790 public override Vector3 Velocity
791 {
792 get {
793 // There's a problem with Vector3.Zero! Don't Use it Here!
794 if (_zeroFlag)
795 return Vector3.Zero;
796 m_lastUpdateSent = false;
797 return _velocity;
798 }
799 set
800 {
801 if (value.IsFinite())
802 {
803 m_pidControllerActive = true;
804 _target_velocity = value;
805 }
806 else
807 {
808 m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character");
809 }
810 }
811 }
812
813 public override Vector3 Torque
814 {
815 get { return Vector3.Zero; }
816 set { return; }
817 }
818
819 public override float CollisionScore
820 {
821 get { return 0f; }
822 set { }
823 }
824
825 public override bool Kinematic
826 {
827 get { return false; }
828 set { }
829 }
830
831 public override Quaternion Orientation
832 {
833 get { return Quaternion.Identity; }
834 set {
835 //Matrix3 or = Orientation.ToRotationMatrix();
836 //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
837 //d.BodySetRotation(Body, ref ord);
838 }
839 }
840
841 public override Vector3 Acceleration
842 {
843 get { return _acceleration; }
844 }
845
846 public void SetAcceleration(Vector3 accel)
847 {
848 m_pidControllerActive = true;
849 _acceleration = accel;
850 }
851
852 /// <summary>
853 /// Adds the force supplied to the Target Velocity
854 /// The PID controller takes this target velocity and tries to make it a reality
855 /// </summary>
856 /// <param name="force"></param>
857 public override void AddForce(Vector3 force, bool pushforce)
858 {
859 if (force.IsFinite())
860 {
861 if (pushforce)
862 {
863 m_pidControllerActive = false;
864 force *= 100f;
865//Console.WriteLine("DF 1"); // ##
866 if (!force.ApproxEquals(Vector3.Zero, 0.01f))
867 doForce(force);
868 // If uncommented, things get pushed off world
869 //
870 // m_log.Debug("Push!");
871 // _target_velocity.X += force.X;
872 // _target_velocity.Y += force.Y;
873 // _target_velocity.Z += force.Z;
874 }
875 else
876 {
877 m_pidControllerActive = true;
878 _target_velocity.X += force.X;
879 _target_velocity.Y += force.Y;
880 _target_velocity.Z += force.Z;
881 }
882 }
883 else
884 {
885 m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character");
886 }
887 //m_lastUpdateSent = false;
888 }
889
890 public override void AddAngularForce(Vector3 force, bool pushforce)
891 {
892
893 }
894
895 /// <summary>
896 /// After all of the forces add up with 'add force' we apply them with doForce
897 /// </summary>
898 /// <param name="force"></param>
899 public void doForce(Vector3 force)
900 {
901 if (!collidelock)
902 {
903 d.BodyAddForce(Body, force.X, force.Y, force.Z);
904 //d.BodySetRotation(Body, ref m_StandUpRotation);
905 //standupStraight();
906 d.Vector3 vel = d.BodyGetLinearVel(Body); //##
907//Console.WriteLine("AvVel <{0},{1},{2}>", vel.X, vel.Y, vel.Z); //##
908 }
909 }
910
911 public override void SetMomentum(Vector3 momentum)
912 {
913 }
914
915
916 /// <summary>
917 /// Called from Simulate
918 /// This is the avatar's movement control + PID Controller
919 /// </summary>
920 /// <param name="timeStep"></param>
921 public void Move(float timeStep, List<OdeCharacter> defects)
922 {
923 // no lock; for now it's only called from within Simulate()
924
925 // If the PID Controller isn't active then we set our force
926 // calculating base velocity to the current position
927
928 if (Body == IntPtr.Zero)
929 return;
930
931 if (m_pidControllerActive == false)
932 {
933 _zeroPosition = d.BodyGetPosition(Body);
934 }
935 //PidStatus = true;
936
937 d.Vector3 localpos = d.BodyGetPosition(Body);
938 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
939
940 if (!localPos.IsFinite())
941 {
942
943 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
944 defects.Add(this);
945 // _parent_scene.RemoveCharacter(this);
946
947 // destroy avatar capsule and related ODE data
948 if (Amotor != IntPtr.Zero)
949 {
950 // Kill the Amotor
951 d.JointDestroy(Amotor);
952 Amotor = IntPtr.Zero;
953 }
954
955 //kill the Geometry
956 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
957
958 if (Body != IntPtr.Zero)
959 {
960 //kill the body
961 d.BodyDestroy(Body);
962
963 Body = IntPtr.Zero;
964 }
965
966 if(Shell != IntPtr.Zero)
967 {
968 try
969 {
970 d.GeomDestroy(Shell);
971 }
972 catch (System.AccessViolationException)
973 {
974 m_log.Error("[PHYSICS]: PrimGeom dead");
975 }
976 // Remove any old entries
977//string tShell;
978//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
979//Console.WriteLine("**** Remove {0}", tShell);
980
981 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
982 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
983 Shell = IntPtr.Zero;
984 }
985
986 return;
987 }
988
989 Vector3 vec = Vector3.Zero;
990 d.Vector3 vel = d.BodyGetLinearVel(Body);
991
992 float movementdivisor = 1f;
993
994 if (!m_alwaysRun)
995 {
996 movementdivisor = walkDivisor;
997 }
998 else
999 {
1000 movementdivisor = runDivisor;
1001 }
1002
1003 // if velocity is zero, use position control; otherwise, velocity control
1004 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
1005 {
1006 // keep track of where we stopped. No more slippin' & slidin'
1007 if (!_zeroFlag)
1008 {
1009 _zeroFlag = true;
1010 _zeroPosition = d.BodyGetPosition(Body);
1011 }
1012 if (m_pidControllerActive)
1013 {
1014 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1015 // react to the physics scene by moving it's position.
1016 // Avatar to Avatar collisions
1017 // Prim to avatar collisions
1018
1019 d.Vector3 pos = d.BodyGetPosition(Body);
1020 float errX = _zeroPosition.X - pos.X;
1021 float errY = _zeroPosition.Y - pos.Y;
1022 if( (Math.Abs(errX) > 0.1f) || (Math.Abs(errY) > 0.1f) )
1023 {
1024 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (errX) * (PID_P * 2);
1025 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (errY) * (PID_P * 2);
1026 }
1027 else
1028 { // close, jump to lateral destination
1029 d.BodySetPosition(Body, _zeroPosition.X, _zeroPosition.Y, pos.Z);
1030 }
1031// if (flying)
1032 if (flying || jumping) // add for jumping
1033 {
1034 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1035 }
1036 }
1037 //PidStatus = true;
1038 }
1039 else
1040 {
1041 m_pidControllerActive = true;
1042 _zeroFlag = false;
1043 if (m_iscolliding && !flying)
1044 {
1045 // We're standing on something
1046 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
1047 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
1048 }
1049 else if (m_iscolliding && flying)
1050 {
1051 // We're flying and colliding with something
1052 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*(PID_D / 16);
1053 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*(PID_D / 16);
1054 }
1055 else if (!m_iscolliding && flying)
1056 {
1057 // we're in mid air suspended
1058 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D/6);
1059 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D/6);
1060 }
1061
1062 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
1063 {
1064 // We're colliding with something and we're not flying but we're moving
1065 // This means we're walking or running.
1066 d.Vector3 pos = d.BodyGetPosition(Body);
1067 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
1068 if (_target_velocity.X > 0)
1069 {
1070 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1071 }
1072 if (_target_velocity.Y > 0)
1073 {
1074 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1075 }
1076 }
1077 else if (!m_iscolliding && !flying)
1078 {
1079 // we're not colliding and we're not flying so that means we're falling!
1080 // m_iscolliding includes collisions with the ground.
1081
1082 // d.Vector3 pos = d.BodyGetPosition(Body);
1083 if (Math.Abs(_target_velocity.X) > 0)
1084 {
1085 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1086 }
1087 if (Math.Abs(_target_velocity.Y) > 0)
1088 {
1089 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1090 }
1091 }
1092
1093 if (flying)
1094 {
1095 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
1096 }
1097 }
1098 if (flying)
1099 {
1100 vec.Z += ((-1 * _parent_scene.gravityz)*m_mass);
1101
1102 //Added for auto fly height. Kitto Flora
1103 //d.Vector3 pos = d.BodyGetPosition(Body);
1104 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
1105
1106 if (_position.Z < target_altitude)
1107 {
1108 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
1109 }
1110 // end add Kitto Flora
1111 }
1112 if (vec.IsFinite())
1113 {
1114 if (!vec.ApproxEquals(Vector3.Zero, 0.02f)) // 0.01 allows 0.002 !!
1115 {
1116//Console.WriteLine("DF 2"); // ##
1117
1118 doForce(vec);
1119 if (!_zeroFlag)
1120 {
1121// AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
1122 }
1123 }
1124 }
1125 else
1126 {
1127 m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()");
1128 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
1129 defects.Add(this);
1130 // _parent_scene.RemoveCharacter(this);
1131 // destroy avatar capsule and related ODE data
1132 if (Amotor != IntPtr.Zero)
1133 {
1134 // Kill the Amotor
1135 d.JointDestroy(Amotor);
1136 Amotor = IntPtr.Zero;
1137 }
1138 //kill the Geometry
1139 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1140
1141 if (Body != IntPtr.Zero)
1142 {
1143 //kill the body
1144 d.BodyDestroy(Body);
1145
1146 Body = IntPtr.Zero;
1147 }
1148
1149 if(Shell != IntPtr.Zero)
1150 {
1151 try
1152 {
1153 d.GeomDestroy(Shell);
1154 }
1155 catch (System.AccessViolationException)
1156 {
1157 m_log.Error("[PHYSICS]: PrimGeom dead");
1158 }
1159 // Remove any old entries
1160//string tShell;
1161//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1162//Console.WriteLine("**** Remove {0}", tShell);
1163
1164 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1165 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1166 Shell = IntPtr.Zero;
1167 }
1168 }
1169 }
1170
1171 /// <summary>
1172 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
1173 /// </summary>
1174 public void UpdatePositionAndVelocity()
1175 {
1176 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
1177 d.Vector3 vec;
1178 try
1179 {
1180 vec = d.BodyGetPosition(Body);
1181 }
1182 catch (NullReferenceException)
1183 {
1184 bad = true;
1185 _parent_scene.BadCharacter(this);
1186 vec = new d.Vector3(_position.X, _position.Y, _position.Z);
1187 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1188 m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid);
1189 }
1190
1191
1192 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1193 if (vec.X < 0.0f) vec.X = 0.0f;
1194 if (vec.Y < 0.0f) vec.Y = 0.0f;
1195 if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1196 if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1197
1198 _position.X = vec.X;
1199 _position.Y = vec.Y;
1200 _position.Z = vec.Z;
1201
1202 // Did we move last? = zeroflag
1203 // This helps keep us from sliding all over
1204
1205 if (_zeroFlag)
1206 {
1207 _velocity.X = 0.0f;
1208 _velocity.Y = 0.0f;
1209 _velocity.Z = 0.0f;
1210
1211 // Did we send out the 'stopped' message?
1212 if (!m_lastUpdateSent)
1213 {
1214 m_lastUpdateSent = true;
1215 //base.RequestPhysicsterseUpdate();
1216
1217 }
1218 }
1219 else
1220 {
1221 m_lastUpdateSent = false;
1222 try
1223 {
1224 vec = d.BodyGetLinearVel(Body);
1225 }
1226 catch (NullReferenceException)
1227 {
1228 vec.X = _velocity.X;
1229 vec.Y = _velocity.Y;
1230 vec.Z = _velocity.Z;
1231 }
1232 _velocity.X = (vec.X);
1233 _velocity.Y = (vec.Y);
1234
1235 _velocity.Z = (vec.Z);
1236
1237 if (_velocity.Z < -6 && !m_hackSentFall)
1238 {
1239 m_hackSentFall = true;
1240 m_pidControllerActive = false;
1241 }
1242 else if (flying && !m_hackSentFly)
1243 {
1244 //m_hackSentFly = true;
1245 //base.SendCollisionUpdate(new CollisionEventUpdate());
1246 }
1247 else
1248 {
1249 m_hackSentFly = false;
1250 m_hackSentFall = false;
1251 }
1252 }
1253 }
1254
1255 /// <summary>
1256 /// Cleanup the things we use in the scene.
1257 /// </summary>
1258 public void Destroy()
1259 {
1260 m_tainted_isPhysical = false;
1261 _parent_scene.AddPhysicsActorTaint(this);
1262 }
1263
1264 public override void CrossingFailure()
1265 {
1266 }
1267
1268 public override Vector3 PIDTarget { set { return; } }
1269 public override bool PIDActive { set { return; } }
1270 public override float PIDTau { set { return; } }
1271
1272 public override float PIDHoverHeight { set { return; } }
1273 public override bool PIDHoverActive { set { return; } }
1274 public override PIDHoverType PIDHoverType { set { return; } }
1275 public override float PIDHoverTau { set { return; } }
1276
1277 public override Quaternion APIDTarget{ set { return; } }
1278
1279 public override bool APIDActive{ set { return; } }
1280
1281 public override float APIDStrength{ set { return; } }
1282
1283 public override float APIDDamping{ set { return; } }
1284
1285
1286 public override void SubscribeEvents(int ms)
1287 {
1288 m_requestedUpdateFrequency = ms;
1289 m_eventsubscription = ms;
1290 _parent_scene.addCollisionEventReporting(this);
1291 }
1292 public override void UnSubscribeEvents()
1293 {
1294 _parent_scene.remCollisionEventReporting(this);
1295 m_requestedUpdateFrequency = 0;
1296 m_eventsubscription = 0;
1297 }
1298 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1299 {
1300 if (m_eventsubscription > 0)
1301 {
1302 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
1303 }
1304 }
1305
1306 public void SendCollisions()
1307 {
1308 if (m_eventsubscription > m_requestedUpdateFrequency)
1309 {
1310 if (CollisionEventsThisFrame != null)
1311 {
1312 base.SendCollisionUpdate(CollisionEventsThisFrame);
1313 }
1314 CollisionEventsThisFrame = new CollisionEventUpdate();
1315 m_eventsubscription = 0;
1316 }
1317 }
1318 public override bool SubscribedEvents()
1319 {
1320 if (m_eventsubscription > 0)
1321 return true;
1322 return false;
1323 }
1324
1325 public void ProcessTaints(float timestep)
1326 {
1327 lock (m_syncRoot)
1328 {
1329
1330 if (m_tainted_isPhysical != m_isPhysical)
1331 {
1332 if (m_tainted_isPhysical)
1333 {
1334 // Create avatar capsule and related ODE data
1335 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1336 {
1337 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1338 + (Shell!=IntPtr.Zero ? "Shell ":"")
1339 + (Body!=IntPtr.Zero ? "Body ":"")
1340 + (Amotor!=IntPtr.Zero ? "Amotor ":""));
1341 }
1342 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor);
1343 _parent_scene.AddCharacter(this);
1344 }
1345 else
1346 {
1347 _parent_scene.RemoveCharacter(this);
1348 // destroy avatar capsule and related ODE data
1349 if (Amotor != IntPtr.Zero)
1350 {
1351 // Kill the Amotor
1352 d.JointDestroy(Amotor);
1353 Amotor = IntPtr.Zero;
1354 }
1355 //kill the Geometry
1356 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1357
1358 if (Body != IntPtr.Zero)
1359 {
1360 //kill the body
1361 d.BodyDestroy(Body);
1362 Body = IntPtr.Zero;
1363 }
1364
1365 if(Shell != IntPtr.Zero)
1366 {
1367 try
1368 {
1369 d.GeomDestroy(Shell);
1370 }
1371 catch (System.AccessViolationException)
1372 {
1373 m_log.Error("[PHYSICS]: PrimGeom dead");
1374 }
1375 // Remove any old entries
1376 //string tShell;
1377 //_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1378 //Console.WriteLine("**** Remove {0}", tShell);
1379
1380 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1381 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1382 Shell = IntPtr.Zero;
1383 }
1384 }
1385
1386 m_isPhysical = m_tainted_isPhysical;
1387 }
1388
1389 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1390 {
1391 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1392 {
1393
1394 m_pidControllerActive = true;
1395 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1396 d.JointDestroy(Amotor);
1397 float prevCapsule = CAPSULE_LENGTH;
1398 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1399 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
1400 d.BodyDestroy(Body);
1401 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1402 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1403 Velocity = Vector3.Zero;
1404 }
1405 else
1406 {
1407 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
1408 + (Shell==IntPtr.Zero ? "Shell ":"")
1409 + (Body==IntPtr.Zero ? "Body ":"")
1410 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1411 }
1412 }
1413
1414 if (!m_taintPosition.ApproxEquals(_position, 0.05f))
1415 {
1416 if (Body != IntPtr.Zero)
1417 {
1418 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1419
1420 _position.X = m_taintPosition.X;
1421 _position.Y = m_taintPosition.Y;
1422 _position.Z = m_taintPosition.Z;
1423 }
1424 }
1425
1426 }
1427 }
1428
1429 internal void AddCollisionFrameTime(int p)
1430 {
1431 // protect it from overflow crashing
1432 if (m_eventsubscription + p >= int.MaxValue)
1433 m_eventsubscription = 0;
1434 m_eventsubscription += p;
1435 }
1436 }
1437}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..8402082
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3861 @@
1/* Copyright (c) Contributors, http://opensimulator.org/
2 * See CONTRIBUTORS.TXT for a full list of copyright holders.
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * * Neither the name of the OpenSimulator Project nor the
11 * names of its contributors may be used to endorse or promote products
12 * derived from this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Revised March 5th 2010 by Kitto Flora. ODEDynamics.cs
26 * rolled into ODEPrim.cs
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Runtime.InteropServices;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using Ode.NET;
37using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager;
39
40
41namespace OpenSim.Region.Physics.OdePlugin
42{
43 /// <summary>
44 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
45 /// </summary>
46
47 public class OdePrim : PhysicsActor
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private Vector3 _position;
52 private Vector3 _velocity;
53 private Vector3 _torque;
54 private Vector3 m_lastVelocity;
55 private Vector3 m_lastposition;
56 private Quaternion m_lastorientation = new Quaternion();
57 private Vector3 m_rotationalVelocity;
58 private Vector3 _size;
59 private Vector3 _acceleration;
60 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
61 private Quaternion _orientation;
62 private Vector3 m_taintposition;
63 private Vector3 m_taintsize;
64 private Vector3 m_taintVelocity;
65 private Vector3 m_taintTorque;
66 private Quaternion m_taintrot;
67 private Vector3 m_rotateEnable = Vector3.One; // Current setting
68 private Vector3 m_rotateEnableRequest = Vector3.One; // Request from LSL
69 private bool m_rotateEnableUpdate = false;
70 private Vector3 m_lockX;
71 private Vector3 m_lockY;
72 private Vector3 m_lockZ;
73 private IntPtr Amotor = IntPtr.Zero;
74 private IntPtr AmotorX = IntPtr.Zero;
75 private IntPtr AmotorY = IntPtr.Zero;
76 private IntPtr AmotorZ = IntPtr.Zero;
77
78 private Vector3 m_PIDTarget;
79 private float m_PIDTau;
80 private float PID_D = 35f;
81 private float PID_G = 25f;
82 private bool m_usePID = false;
83
84 private Quaternion m_APIDTarget = new Quaternion();
85 private float m_APIDStrength = 0.5f;
86 private float m_APIDDamping = 0.5f;
87 private bool m_useAPID = false;
88 private float m_APIDdamper = 1.0f;
89
90 // These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
91 // do not confuse with VEHICLE HOVER
92
93 private float m_PIDHoverHeight;
94 private float m_PIDHoverTau;
95 private bool m_useHoverPID;
96 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
97 private float m_targetHoverHeight;
98 private float m_groundHeight;
99 private float m_waterHeight;
100 private float m_buoyancy; //m_buoyancy set by llSetBuoyancy()
101
102 // private float m_tensor = 5f;
103 private int body_autodisable_frames = 20;
104
105
106 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
107 | CollisionCategories.Space
108 | CollisionCategories.Body
109 | CollisionCategories.Character
110 );
111 private bool m_taintshape;
112 private bool m_taintPhysics;
113 private bool m_collidesLand = true;
114 private bool m_collidesWater;
115 public bool m_returnCollisions;
116
117 // Default we're a Geometry
118 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
119
120 // Default, Collide with Other Geometries, spaces and Bodies
121 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
122
123 public bool m_taintremove;
124 public bool m_taintdisable;
125 public bool m_disabled;
126 public bool m_taintadd;
127 public bool m_taintselected;
128 public bool m_taintCollidesWater;
129
130 public uint m_localID;
131
132 //public GCHandle gc;
133 private CollisionLocker ode;
134
135 private bool m_meshfailed = false;
136 private bool m_taintforce = false;
137 private bool m_taintaddangularforce = false;
138 private Vector3 m_force;
139 private List<Vector3> m_forcelist = new List<Vector3>();
140 private List<Vector3> m_angularforcelist = new List<Vector3>();
141
142 private IMesh _mesh;
143 private PrimitiveBaseShape _pbs;
144 private OdeScene _parent_scene;
145 public IntPtr m_targetSpace = IntPtr.Zero;
146 public IntPtr prim_geom;
147// public IntPtr prev_geom;
148 public IntPtr _triMeshData;
149
150 private IntPtr _linkJointGroup = IntPtr.Zero;
151 private PhysicsActor _parent;
152 private PhysicsActor m_taintparent;
153
154 private List<OdePrim> childrenPrim = new List<OdePrim>();
155
156 private bool iscolliding;
157 private bool m_isphysical;
158 private bool m_isSelected;
159
160 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
161
162 private bool m_throttleUpdates;
163 private int throttleCounter;
164 public int m_interpenetrationcount;
165 public float m_collisionscore;
166 public int m_roundsUnderMotionThreshold;
167 private int m_crossingfailures;
168
169 public bool outofBounds;
170 private float m_density = 10.000006836f; // Aluminum g/cm3;
171
172 public bool _zeroFlag; // if body has been stopped
173 private bool m_lastUpdateSent;
174
175 public IntPtr Body = IntPtr.Zero;
176 public String m_primName;
177 private Vector3 _target_velocity;
178 public d.Mass pMass;
179
180 public int m_eventsubscription;
181 private CollisionEventUpdate CollisionEventsThisFrame;
182
183 private IntPtr m_linkJoint = IntPtr.Zero;
184
185 public volatile bool childPrim;
186
187 internal int m_material = (int)Material.Wood;
188
189 private int frcount = 0; // Used to limit dynamics debug output to
190 private int revcount = 0; // Reverse motion while > 0
191
192 private IntPtr m_body = IntPtr.Zero;
193
194 // Vehicle properties ============================================================================================
195 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
196 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
197 private VehicleFlag m_flags = (VehicleFlag) 0; // Bit settings:
198 // HOVER_TERRAIN_ONLY
199 // HOVER_GLOBAL_HEIGHT
200 // NO_DEFLECTION_UP
201 // HOVER_WATER_ONLY
202 // HOVER_UP_ONLY
203 // LIMIT_MOTOR_UP
204 // LIMIT_ROLL_ONLY
205
206 // Linear properties
207 private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity
208 //requested by LSL
209 private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL
210 private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL
211 private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL
212
213 private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor
214 private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity
215 private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity
216
217 //Angular properties
218 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
219
220 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
221 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
222 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
223
224 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
225// private Vector3 m_angObjectVel = Vector3.Zero; // current body angular velocity
226 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
227
228 //Deflection properties
229 // private float m_angularDeflectionEfficiency = 0;
230 // private float m_angularDeflectionTimescale = 0;
231 // private float m_linearDeflectionEfficiency = 0;
232 // private float m_linearDeflectionTimescale = 0;
233
234 //Banking properties
235 // private float m_bankingEfficiency = 0;
236 // private float m_bankingMix = 0;
237 // private float m_bankingTimescale = 0;
238
239 //Hover and Buoyancy properties
240 private float m_VhoverHeight = 0f;
241// private float m_VhoverEfficiency = 0f;
242 private float m_VhoverTimescale = 0f;
243 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
244 private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle.
245 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
246 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
247 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
248
249 //Attractor properties
250 private float m_verticalAttractionEfficiency = 1.0f; // damped
251 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
252
253
254
255
256
257
258 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
259 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
260 {
261 ode = dode;
262 if (!pos.IsFinite())
263 {
264 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
265 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
266 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
267 }
268
269 _position = pos;
270 m_taintposition = pos;
271 PID_D = parent_scene.bodyPIDD;
272 PID_G = parent_scene.bodyPIDG;
273 m_density = parent_scene.geomDefaultDensity;
274 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
275 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
276
277
278 prim_geom = IntPtr.Zero;
279// prev_geom = IntPtr.Zero;
280
281 if (!pos.IsFinite())
282 {
283 size = new Vector3(0.5f, 0.5f, 0.5f);
284 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
285 }
286
287 if (size.X <= 0) size.X = 0.01f;
288 if (size.Y <= 0) size.Y = 0.01f;
289 if (size.Z <= 0) size.Z = 0.01f;
290
291 _size = size;
292 m_taintsize = _size;
293
294 if (!QuaternionIsFinite(rotation))
295 {
296 rotation = Quaternion.Identity;
297 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
298 }
299
300 _orientation = rotation;
301 m_taintrot = _orientation;
302 _mesh = mesh;
303 _pbs = pbs;
304
305 _parent_scene = parent_scene;
306 m_targetSpace = (IntPtr)0;
307
308// if (pos.Z < 0)
309 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
310 m_isphysical = false;
311 else
312 {
313 m_isphysical = pisPhysical;
314 // If we're physical, we need to be in the master space for now.
315 // linksets *should* be in a space together.. but are not currently
316 if (m_isphysical)
317 m_targetSpace = _parent_scene.space;
318 }
319 m_primName = primName;
320 m_taintadd = true;
321 _parent_scene.AddPhysicsActorTaint(this);
322 // don't do .add() here; old geoms get recycled with the same hash
323 }
324
325 public override int PhysicsActorType
326 {
327 get { return (int) ActorTypes.Prim; }
328 set { return; }
329 }
330
331 public override bool SetAlwaysRun
332 {
333 get { return false; }
334 set { return; }
335 }
336
337 public override uint LocalID
338 {
339 set {
340 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
341 m_localID = value; }
342 }
343
344 public override bool Grabbed
345 {
346 set { return; }
347 }
348
349 public override bool Selected
350 {
351 set {
352
353//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
354 // This only makes the object not collidable if the object
355 // is physical or the object is modified somehow *IN THE FUTURE*
356 // without this, if an avatar selects prim, they can walk right
357 // through it while it's selected
358 m_collisionscore = 0;
359 if ((m_isphysical && !_zeroFlag) || !value)
360 {
361 m_taintselected = value;
362 _parent_scene.AddPhysicsActorTaint(this);
363 }
364 else
365 {
366 m_taintselected = value;
367 m_isSelected = value;
368 }
369 if(m_isSelected) disableBodySoft();
370 }
371 }
372
373 public override bool IsPhysical
374 {
375 get { return m_isphysical; }
376 set
377 {
378 m_isphysical = value;
379 if (!m_isphysical)
380 { // Zero the remembered last velocity
381 m_lastVelocity = Vector3.Zero;
382 if (m_type != Vehicle.TYPE_NONE) Halt();
383 }
384 }
385 }
386
387 public void setPrimForRemoval()
388 {
389 m_taintremove = true;
390 }
391
392 public override bool Flying
393 {
394 // no flying prims for you
395 get { return false; }
396 set { }
397 }
398
399 public override bool IsColliding
400 {
401 get { return iscolliding; }
402 set { iscolliding = value; }
403 }
404
405 public override bool CollidingGround
406 {
407 get { return false; }
408 set { return; }
409 }
410
411 public override bool CollidingObj
412 {
413 get { return false; }
414 set { return; }
415 }
416
417 public override bool ThrottleUpdates
418 {
419 get { return m_throttleUpdates; }
420 set { m_throttleUpdates = value; }
421 }
422
423 public override bool Stopped
424 {
425 get { return _zeroFlag; }
426 }
427
428 public override Vector3 Position
429 {
430 get { return _position; }
431
432 set { _position = value;
433 //m_log.Info("[PHYSICS]: " + _position.ToString());
434 }
435 }
436
437 public override Vector3 Size
438 {
439 get { return _size; }
440 set
441 {
442 if (value.IsFinite())
443 {
444 _size = value;
445 }
446 else
447 {
448 m_log.Warn("[PHYSICS]: Got NaN Size on object");
449 }
450 }
451 }
452
453 public override float Mass
454 {
455 get { return CalculateMass(); }
456 }
457
458 public override Vector3 Force
459 {
460 //get { return Vector3.Zero; }
461 get { return m_force; }
462 set
463 {
464 if (value.IsFinite())
465 {
466 m_force = value;
467 }
468 else
469 {
470 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
471 }
472 }
473 }
474
475 public override int VehicleType
476 {
477 get { return (int)m_type; }
478 set { ProcessTypeChange((Vehicle)value); }
479 }
480
481 public override void VehicleFloatParam(int param, float value)
482 {
483 ProcessFloatVehicleParam((Vehicle) param, value);
484 }
485
486 public override void VehicleVectorParam(int param, Vector3 value)
487 {
488 ProcessVectorVehicleParam((Vehicle) param, value);
489 }
490
491 public override void VehicleRotationParam(int param, Quaternion rotation)
492 {
493 ProcessRotationVehicleParam((Vehicle) param, rotation);
494 }
495
496 public override void VehicleFlags(int param, bool remove)
497 {
498 ProcessVehicleFlags(param, remove);
499 }
500
501 public override void SetVolumeDetect(int param)
502 {
503 lock (_parent_scene.OdeLock)
504 {
505 m_isVolumeDetect = (param!=0);
506 }
507 }
508
509 public override Vector3 CenterOfMass
510 {
511 get { return Vector3.Zero; }
512 }
513
514 public override Vector3 GeometricCenter
515 {
516 get { return Vector3.Zero; }
517 }
518
519 public override PrimitiveBaseShape Shape
520 {
521 set
522 {
523 _pbs = value;
524 m_taintshape = true;
525 }
526 }
527
528 public override Vector3 Velocity
529 {
530 get
531 {
532 // Averate previous velocity with the new one so
533 // client object interpolation works a 'little' better
534 if (_zeroFlag)
535 return Vector3.Zero;
536
537 Vector3 returnVelocity = Vector3.Zero;
538 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
539 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
540 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
541 return returnVelocity;
542 }
543 set
544 {
545 if (value.IsFinite())
546 {
547 _velocity = value;
548
549 m_taintVelocity = value;
550 _parent_scene.AddPhysicsActorTaint(this);
551 }
552 else
553 {
554 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
555 }
556
557 }
558 }
559
560 public override Vector3 Torque
561 {
562 get
563 {
564 if (!m_isphysical || Body == IntPtr.Zero)
565 return Vector3.Zero;
566
567 return _torque;
568 }
569
570 set
571 {
572 if (value.IsFinite())
573 {
574 m_taintTorque = value;
575 _parent_scene.AddPhysicsActorTaint(this);
576 }
577 else
578 {
579 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
580 }
581 }
582 }
583
584 public override float CollisionScore
585 {
586 get { return m_collisionscore; }
587 set { m_collisionscore = value; }
588 }
589
590 public override bool Kinematic
591 {
592 get { return false; }
593 set { }
594 }
595
596 public override Quaternion Orientation
597 {
598 get { return _orientation; }
599 set
600 {
601 if (QuaternionIsFinite(value))
602 {
603 _orientation = value;
604 }
605 else
606 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
607
608 }
609 }
610
611
612 public override bool FloatOnWater
613 {
614 set {
615 m_taintCollidesWater = value;
616 _parent_scene.AddPhysicsActorTaint(this);
617 }
618 }
619
620 public override void SetMomentum(Vector3 momentum)
621 {
622 }
623
624 public override Vector3 PIDTarget
625 {
626 set
627 {
628 if (value.IsFinite())
629 {
630 m_PIDTarget = value;
631 }
632 else
633 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
634 }
635 }
636 public override bool PIDActive { set { m_usePID = value; } }
637 public override float PIDTau { set { m_PIDTau = value; } }
638
639 // For RotLookAt
640 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
641 public override bool APIDActive { set { m_useAPID = value; } }
642 public override float APIDStrength { set { m_APIDStrength = value; } }
643 public override float APIDDamping { set { m_APIDDamping = value; } }
644
645 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
646 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
647 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
648 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
649
650 internal static bool QuaternionIsFinite(Quaternion q)
651 {
652 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
653 return false;
654 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
655 return false;
656 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
657 return false;
658 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
659 return false;
660 return true;
661 }
662
663 public override Vector3 Acceleration // client updates read data via here
664 {
665 get { return _acceleration; }
666 }
667
668
669 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
670 {
671 _acceleration = accel;
672 }
673
674 public override void AddForce(Vector3 force, bool pushforce)
675 {
676 if (force.IsFinite())
677 {
678 lock (m_forcelist)
679 m_forcelist.Add(force);
680
681 m_taintforce = true;
682 }
683 else
684 {
685 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
686 }
687 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
688 }
689
690 public override void AddAngularForce(Vector3 force, bool pushforce)
691 {
692 if (force.IsFinite())
693 {
694 m_angularforcelist.Add(force);
695 m_taintaddangularforce = true;
696 }
697 else
698 {
699 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
700 }
701 }
702
703 public override Vector3 RotationalVelocity
704 {
705 get
706 {
707 return m_rotationalVelocity;
708 }
709 set
710 {
711 if (value.IsFinite())
712 {
713 m_rotationalVelocity = value;
714 }
715 else
716 {
717 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
718 }
719 }
720 }
721
722 public override void CrossingFailure()
723 {
724 m_crossingfailures++;
725 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
726 {
727 base.RaiseOutOfBounds(_position);
728 return;
729 }
730 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
731 {
732 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
733 }
734 }
735
736 public override float Buoyancy
737 {
738 get { return m_buoyancy; }
739 set { m_buoyancy = value; }
740 }
741
742 public override void link(PhysicsActor obj)
743 {
744 m_taintparent = obj;
745 }
746
747 public override void delink()
748 {
749 m_taintparent = null;
750 }
751
752 public override void LockAngularMotion(Vector3 axis)
753 {
754 // This is actually ROTATION ENABLE, not a lock.
755 // default is <1,1,1> which is all enabled.
756 // The lock value is updated inside Move(), no point in using the taint system.
757 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
758 if (axis.IsFinite())
759 {
760 axis.X = (axis.X > 0) ? 1f : 0f;
761 axis.Y = (axis.Y > 0) ? 1f : 0f;
762 axis.Z = (axis.Z > 0) ? 1f : 0f;
763 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
764 m_rotateEnableRequest = axis;
765 m_rotateEnableUpdate = true;
766 }
767 else
768 {
769 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
770 }
771 }
772
773
774 public void SetGeom(IntPtr geom)
775 {
776 if(prim_geom != IntPtr.Zero)
777 {
778 // Remove any old entries
779//string tPA;
780//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
781//Console.WriteLine("**** Remove {0}", tPA);
782 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
783 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
784 d.GeomDestroy(prim_geom);
785 }
786
787 prim_geom = geom;
788//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
789 if (prim_geom != IntPtr.Zero)
790 {
791 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
792 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
793 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
794 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
795//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
796 }
797
798 if (childPrim)
799 {
800 if (_parent != null && _parent is OdePrim)
801 {
802 OdePrim parent = (OdePrim)_parent;
803//Console.WriteLine("SetGeom calls ChildSetGeom");
804 parent.ChildSetGeom(this);
805 }
806 }
807 //m_log.Warn("Setting Geom to: " + prim_geom);
808 }
809
810 public void enableBodySoft()
811 {
812 if (!childPrim)
813 {
814 if (m_isphysical && Body != IntPtr.Zero)
815 {
816 d.BodyEnable(Body);
817 if (m_type != Vehicle.TYPE_NONE)
818 Enable(Body, _parent_scene);
819 }
820
821 m_disabled = false;
822 }
823 }
824
825 public void disableBodySoft()
826 {
827 m_disabled = true;
828
829 if (m_isphysical && Body != IntPtr.Zero)
830 {
831 d.BodyDisable(Body);
832 Halt();
833 }
834 }
835
836 public void enableBody()
837 {
838 // Don't enable this body if we're a child prim
839 // this should be taken care of in the parent function not here
840 if (!childPrim)
841 {
842 // Sets the geom to a body
843 Body = d.BodyCreate(_parent_scene.world);
844
845 setMass();
846 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
847 d.Quaternion myrot = new d.Quaternion();
848 myrot.X = _orientation.X;
849 myrot.Y = _orientation.Y;
850 myrot.Z = _orientation.Z;
851 myrot.W = _orientation.W;
852 d.BodySetQuaternion(Body, ref myrot);
853 d.GeomSetBody(prim_geom, Body);
854 m_collisionCategories |= CollisionCategories.Body;
855 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
856
857 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
858 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
859
860 d.BodySetAutoDisableFlag(Body, true);
861 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
862
863 // disconnect from world gravity so we can apply buoyancy
864 d.BodySetGravityMode (Body, false);
865
866 m_interpenetrationcount = 0;
867 m_collisionscore = 0;
868 m_disabled = false;
869
870 if (m_type != Vehicle.TYPE_NONE)
871 {
872 Enable(Body, _parent_scene);
873 }
874
875 _parent_scene.addActivePrim(this);
876 }
877 }
878
879 #region Mass Calculation
880
881 private float CalculateMass()
882 {
883 float volume = _size.X * _size.Y * _size.Z; // default
884 float tmp;
885
886 float returnMass = 0;
887 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
888 float hollowVolume = hollowAmount * hollowAmount;
889
890 switch (_pbs.ProfileShape)
891 {
892 case ProfileShape.Square:
893 // default box
894
895 if (_pbs.PathCurve == (byte)Extrusion.Straight)
896 {
897 if (hollowAmount > 0.0)
898 {
899 switch (_pbs.HollowShape)
900 {
901 case HollowShape.Square:
902 case HollowShape.Same:
903 break;
904
905 case HollowShape.Circle:
906
907 hollowVolume *= 0.78539816339f;
908 break;
909
910 case HollowShape.Triangle:
911
912 hollowVolume *= (0.5f * .5f);
913 break;
914
915 default:
916 hollowVolume = 0;
917 break;
918 }
919 volume *= (1.0f - hollowVolume);
920 }
921 }
922
923 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
924 {
925 //a tube
926
927 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
928 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
929 volume -= volume*tmp*tmp;
930
931 if (hollowAmount > 0.0)
932 {
933 hollowVolume *= hollowAmount;
934
935 switch (_pbs.HollowShape)
936 {
937 case HollowShape.Square:
938 case HollowShape.Same:
939 break;
940
941 case HollowShape.Circle:
942 hollowVolume *= 0.78539816339f;;
943 break;
944
945 case HollowShape.Triangle:
946 hollowVolume *= 0.5f * 0.5f;
947 break;
948 default:
949 hollowVolume = 0;
950 break;
951 }
952 volume *= (1.0f - hollowVolume);
953 }
954 }
955
956 break;
957
958 case ProfileShape.Circle:
959
960 if (_pbs.PathCurve == (byte)Extrusion.Straight)
961 {
962 volume *= 0.78539816339f; // elipse base
963
964 if (hollowAmount > 0.0)
965 {
966 switch (_pbs.HollowShape)
967 {
968 case HollowShape.Same:
969 case HollowShape.Circle:
970 break;
971
972 case HollowShape.Square:
973 hollowVolume *= 0.5f * 2.5984480504799f;
974 break;
975
976 case HollowShape.Triangle:
977 hollowVolume *= .5f * 1.27323954473516f;
978 break;
979
980 default:
981 hollowVolume = 0;
982 break;
983 }
984 volume *= (1.0f - hollowVolume);
985 }
986 }
987
988 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
989 {
990 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
991 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
992 volume *= (1.0f - tmp * tmp);
993
994 if (hollowAmount > 0.0)
995 {
996
997 // calculate the hollow volume by it's shape compared to the prim shape
998 hollowVolume *= hollowAmount;
999
1000 switch (_pbs.HollowShape)
1001 {
1002 case HollowShape.Same:
1003 case HollowShape.Circle:
1004 break;
1005
1006 case HollowShape.Square:
1007 hollowVolume *= 0.5f * 2.5984480504799f;
1008 break;
1009
1010 case HollowShape.Triangle:
1011 hollowVolume *= .5f * 1.27323954473516f;
1012 break;
1013
1014 default:
1015 hollowVolume = 0;
1016 break;
1017 }
1018 volume *= (1.0f - hollowVolume);
1019 }
1020 }
1021 break;
1022
1023 case ProfileShape.HalfCircle:
1024 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1025 {
1026 volume *= 0.52359877559829887307710723054658f;
1027 }
1028 break;
1029
1030 case ProfileShape.EquilateralTriangle:
1031
1032 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1033 {
1034 volume *= 0.32475953f;
1035
1036 if (hollowAmount > 0.0)
1037 {
1038
1039 // calculate the hollow volume by it's shape compared to the prim shape
1040 switch (_pbs.HollowShape)
1041 {
1042 case HollowShape.Same:
1043 case HollowShape.Triangle:
1044 hollowVolume *= .25f;
1045 break;
1046
1047 case HollowShape.Square:
1048 hollowVolume *= 0.499849f * 3.07920140172638f;
1049 break;
1050
1051 case HollowShape.Circle:
1052 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1053 // Cyllinder hollow volume calculation
1054
1055 hollowVolume *= 0.1963495f * 3.07920140172638f;
1056 break;
1057
1058 default:
1059 hollowVolume = 0;
1060 break;
1061 }
1062 volume *= (1.0f - hollowVolume);
1063 }
1064 }
1065 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1066 {
1067 volume *= 0.32475953f;
1068 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1069 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1070 volume *= (1.0f - tmp * tmp);
1071
1072 if (hollowAmount > 0.0)
1073 {
1074
1075 hollowVolume *= hollowAmount;
1076
1077 switch (_pbs.HollowShape)
1078 {
1079 case HollowShape.Same:
1080 case HollowShape.Triangle:
1081 hollowVolume *= .25f;
1082 break;
1083
1084 case HollowShape.Square:
1085 hollowVolume *= 0.499849f * 3.07920140172638f;
1086 break;
1087
1088 case HollowShape.Circle:
1089
1090 hollowVolume *= 0.1963495f * 3.07920140172638f;
1091 break;
1092
1093 default:
1094 hollowVolume = 0;
1095 break;
1096 }
1097 volume *= (1.0f - hollowVolume);
1098 }
1099 }
1100 break;
1101
1102 default:
1103 break;
1104 }
1105
1106
1107
1108 float taperX1;
1109 float taperY1;
1110 float taperX;
1111 float taperY;
1112 float pathBegin;
1113 float pathEnd;
1114 float profileBegin;
1115 float profileEnd;
1116
1117 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1118 {
1119 taperX1 = _pbs.PathScaleX * 0.01f;
1120 if (taperX1 > 1.0f)
1121 taperX1 = 2.0f - taperX1;
1122 taperX = 1.0f - taperX1;
1123
1124 taperY1 = _pbs.PathScaleY * 0.01f;
1125 if (taperY1 > 1.0f)
1126 taperY1 = 2.0f - taperY1;
1127 taperY = 1.0f - taperY1;
1128 }
1129 else
1130 {
1131 taperX = _pbs.PathTaperX * 0.01f;
1132 if (taperX < 0.0f)
1133 taperX = -taperX;
1134 taperX1 = 1.0f - taperX;
1135
1136 taperY = _pbs.PathTaperY * 0.01f;
1137 if (taperY < 0.0f)
1138 taperY = -taperY;
1139 taperY1 = 1.0f - taperY;
1140
1141 }
1142
1143
1144 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1145
1146 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1147 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1148 volume *= (pathEnd - pathBegin);
1149
1150// this is crude aproximation
1151 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1152 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1153 volume *= (profileEnd - profileBegin);
1154
1155 returnMass = m_density * volume;
1156
1157 if (returnMass <= 0)
1158 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1159// else if (returnMass > _parent_scene.maximumMassObject)
1160// returnMass = _parent_scene.maximumMassObject;
1161
1162
1163
1164
1165 // Recursively calculate mass
1166 bool HasChildPrim = false;
1167 lock (childrenPrim)
1168 {
1169 if (childrenPrim.Count > 0)
1170 {
1171 HasChildPrim = true;
1172 }
1173
1174 }
1175 if (HasChildPrim)
1176 {
1177 OdePrim[] childPrimArr = new OdePrim[0];
1178
1179 lock (childrenPrim)
1180 childPrimArr = childrenPrim.ToArray();
1181
1182 for (int i = 0; i < childPrimArr.Length; i++)
1183 {
1184 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1185 returnMass += childPrimArr[i].CalculateMass();
1186 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1187 if (i > 256)
1188 break;
1189 }
1190 }
1191 if (returnMass > _parent_scene.maximumMassObject)
1192 returnMass = _parent_scene.maximumMassObject;
1193 return returnMass;
1194 }// end CalculateMass
1195
1196 #endregion
1197
1198 public void setMass()
1199 {
1200 if (Body != (IntPtr) 0)
1201 {
1202 float newmass = CalculateMass();
1203
1204 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1205
1206 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1207 d.BodySetMass(Body, ref pMass);
1208 }
1209 }
1210
1211 public void disableBody()
1212 {
1213 //this kills the body so things like 'mesh' can re-create it.
1214 lock (this)
1215 {
1216 if (!childPrim)
1217 {
1218 if (Body != IntPtr.Zero)
1219 {
1220 _parent_scene.remActivePrim(this);
1221 m_collisionCategories &= ~CollisionCategories.Body;
1222 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1223
1224 if (prim_geom != IntPtr.Zero)
1225 {
1226 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1227 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1228 }
1229
1230
1231 d.BodyDestroy(Body);
1232 lock (childrenPrim)
1233 {
1234 if (childrenPrim.Count > 0)
1235 {
1236 foreach (OdePrim prm in childrenPrim)
1237 {
1238 _parent_scene.remActivePrim(prm);
1239 prm.Body = IntPtr.Zero;
1240 }
1241 }
1242 }
1243 Body = IntPtr.Zero;
1244 }
1245 }
1246 else
1247 {
1248 _parent_scene.remActivePrim(this);
1249
1250 m_collisionCategories &= ~CollisionCategories.Body;
1251 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1252
1253 if (prim_geom != IntPtr.Zero)
1254 {
1255 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1256 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1257 }
1258
1259
1260 Body = IntPtr.Zero;
1261 }
1262 }
1263 m_disabled = true;
1264 m_collisionscore = 0;
1265 }
1266
1267 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1268
1269 public void setMesh(OdeScene parent_scene, IMesh mesh)
1270 {
1271 // This sleeper is there to moderate how long it takes between
1272 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1273
1274 //Thread.Sleep(10);
1275
1276 //Kill Body so that mesh can re-make the geom
1277 if (IsPhysical && Body != IntPtr.Zero)
1278 {
1279 if (childPrim)
1280 {
1281 if (_parent != null)
1282 {
1283 OdePrim parent = (OdePrim)_parent;
1284 parent.ChildDelink(this);
1285 }
1286 }
1287 else
1288 {
1289 disableBody();
1290 }
1291 }
1292 IntPtr vertices, indices;
1293 int vertexCount, indexCount;
1294 int vertexStride, triStride;
1295 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1296 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1297
1298 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1299 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1300 {
1301 _triMeshData = m_MeshToTriMeshMap[mesh];
1302 }
1303 else
1304 {
1305 _triMeshData = d.GeomTriMeshDataCreate();
1306
1307 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1308 d.GeomTriMeshDataPreprocess(_triMeshData);
1309 m_MeshToTriMeshMap[mesh] = _triMeshData;
1310 }
1311
1312 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1313 try
1314 {
1315 // if (prim_geom == IntPtr.Zero) // setGeom takes care of phys engine recreate and prim_geom pointer
1316 // {
1317 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1318 // }
1319 }
1320 catch (AccessViolationException)
1321 {
1322 m_log.Error("[PHYSICS]: MESH LOCKED");
1323 return;
1324 }
1325
1326
1327 // if (IsPhysical && Body == (IntPtr) 0)
1328 // {
1329 // Recreate the body
1330 // m_interpenetrationcount = 0;
1331 // m_collisionscore = 0;
1332
1333 // enableBody();
1334 // }
1335 }
1336
1337 public void ProcessTaints(float timestep) //=============================================================================
1338 {
1339 if (m_taintadd)
1340 {
1341 changeadd(timestep);
1342 }
1343
1344 if (prim_geom != IntPtr.Zero)
1345 {
1346 if (!_position.ApproxEquals(m_taintposition, 0f))
1347 {
1348 changemove(timestep);
1349 }
1350 if (m_taintrot != _orientation)
1351 {
1352 if(childPrim && IsPhysical) // For physical child prim...
1353 {
1354 rotate(timestep);
1355 // KF: ODE will also rotate the parent prim!
1356 // so rotate the root back to where it was
1357 OdePrim parent = (OdePrim)_parent;
1358 parent.rotate(timestep);
1359 }
1360 else
1361 {
1362 //Just rotate the prim
1363 rotate(timestep);
1364 }
1365 }
1366 //
1367
1368 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1369 {
1370 changePhysicsStatus(timestep);
1371 }//
1372
1373 if (!_size.ApproxEquals(m_taintsize,0f))
1374 changesize(timestep);
1375 //
1376
1377 if (m_taintshape)
1378 changeshape(timestep);
1379 //
1380
1381 if (m_taintforce)
1382 changeAddForce(timestep);
1383
1384 if (m_taintaddangularforce)
1385 changeAddAngularForce(timestep);
1386
1387 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1388 changeSetTorque(timestep);
1389
1390 if (m_taintdisable)
1391 changedisable(timestep);
1392
1393 if (m_taintselected != m_isSelected)
1394 changeSelectedStatus(timestep);
1395
1396 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1397 changevelocity(timestep);
1398
1399 if (m_taintparent != _parent)
1400 changelink(timestep);
1401
1402 if (m_taintCollidesWater != m_collidesWater)
1403 changefloatonwater(timestep);
1404/* obsolete
1405 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1406 changeAngularLock(timestep);
1407 */
1408 }
1409 else
1410 {
1411 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.)");
1412 }
1413 }
1414
1415/* obsolete
1416 private void changeAngularLock(float timestep)
1417 {
1418 if (_parent == null)
1419 {
1420 m_angularLock = m_taintAngularLock;
1421 m_angularLockSet = true;
1422 }
1423 }
1424 */
1425 private void changelink(float timestep)
1426 {
1427 // If the newly set parent is not null
1428 // create link
1429 if (_parent == null && m_taintparent != null)
1430 {
1431 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1432 {
1433 OdePrim obj = (OdePrim)m_taintparent;
1434 //obj.disableBody();
1435 obj.ParentPrim(this);
1436
1437 /*
1438 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1439 {
1440 _linkJointGroup = d.JointGroupCreate(0);
1441 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1442 d.JointAttach(m_linkJoint, obj.Body, Body);
1443 d.JointSetFixed(m_linkJoint);
1444 }
1445 */
1446 }
1447 }
1448 // If the newly set parent is null
1449 // destroy link
1450 else if (_parent != null && m_taintparent == null)
1451 {
1452 if (_parent is OdePrim)
1453 {
1454 OdePrim obj = (OdePrim)_parent;
1455 obj.ChildDelink(this);
1456 childPrim = false;
1457 //_parent = null;
1458 }
1459
1460 /*
1461 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1462 d.JointGroupDestroy(_linkJointGroup);
1463
1464 _linkJointGroup = (IntPtr)0;
1465 m_linkJoint = (IntPtr)0;
1466 */
1467 }
1468
1469 _parent = m_taintparent;
1470 m_taintPhysics = m_isphysical;
1471 }
1472
1473 // I'm the parent
1474 // prim is the child
1475 public void ParentPrim(OdePrim prim)
1476 {
1477 if (this.m_localID != prim.m_localID)
1478 {
1479 if (Body == IntPtr.Zero)
1480 {
1481 Body = d.BodyCreate(_parent_scene.world);
1482 // disconnect from world gravity so we can apply buoyancy
1483 d.BodySetGravityMode (Body, false);
1484
1485 setMass();
1486 }
1487 if (Body != IntPtr.Zero)
1488 {
1489 lock (childrenPrim)
1490 {
1491 if (!childrenPrim.Contains(prim))
1492 {
1493 childrenPrim.Add(prim);
1494
1495 foreach (OdePrim prm in childrenPrim)
1496 {
1497 d.Mass m2;
1498 d.MassSetZero(out m2);
1499 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1500
1501
1502 d.Quaternion quat = new d.Quaternion();
1503 quat.W = prm._orientation.W;
1504 quat.X = prm._orientation.X;
1505 quat.Y = prm._orientation.Y;
1506 quat.Z = prm._orientation.Z;
1507
1508 d.Matrix3 mat = new d.Matrix3();
1509 d.RfromQ(out mat, ref quat);
1510 d.MassRotate(ref m2, ref mat);
1511 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1512 d.MassAdd(ref pMass, ref m2);
1513 }
1514 foreach (OdePrim prm in childrenPrim)
1515 {
1516
1517 prm.m_collisionCategories |= CollisionCategories.Body;
1518 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1519
1520 if (prm.prim_geom == IntPtr.Zero)
1521 {
1522 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1523 continue;
1524 }
1525 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1526 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1527
1528
1529 d.Quaternion quat = new d.Quaternion();
1530 quat.W = prm._orientation.W;
1531 quat.X = prm._orientation.X;
1532 quat.Y = prm._orientation.Y;
1533 quat.Z = prm._orientation.Z;
1534
1535 d.Matrix3 mat = new d.Matrix3();
1536 d.RfromQ(out mat, ref quat);
1537 if (Body != IntPtr.Zero)
1538 {
1539 d.GeomSetBody(prm.prim_geom, Body);
1540 prm.childPrim = true;
1541 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1542 //d.GeomSetOffsetPosition(prim.prim_geom,
1543 // (Position.X - prm.Position.X) - pMass.c.X,
1544 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1545 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1546 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1547 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1548 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1549 d.BodySetMass(Body, ref pMass);
1550 }
1551 else
1552 {
1553 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1554 }
1555
1556
1557 prm.m_interpenetrationcount = 0;
1558 prm.m_collisionscore = 0;
1559 prm.m_disabled = false;
1560
1561 prm.Body = Body;
1562 _parent_scene.addActivePrim(prm);
1563 }
1564 m_collisionCategories |= CollisionCategories.Body;
1565 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1566
1567 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1568 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1569
1570
1571 d.Quaternion quat2 = new d.Quaternion();
1572 quat2.W = _orientation.W;
1573 quat2.X = _orientation.X;
1574 quat2.Y = _orientation.Y;
1575 quat2.Z = _orientation.Z;
1576
1577 d.Matrix3 mat2 = new d.Matrix3();
1578 d.RfromQ(out mat2, ref quat2);
1579 d.GeomSetBody(prim_geom, Body);
1580 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1581 //d.GeomSetOffsetPosition(prim.prim_geom,
1582 // (Position.X - prm.Position.X) - pMass.c.X,
1583 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1584 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1585 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1586 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1587 d.BodySetMass(Body, ref pMass);
1588
1589 d.BodySetAutoDisableFlag(Body, true);
1590 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1591
1592
1593 m_interpenetrationcount = 0;
1594 m_collisionscore = 0;
1595 m_disabled = false;
1596
1597 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1598 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1599 _parent_scene.addActivePrim(this);
1600 }
1601 }
1602 }
1603 }
1604
1605 }
1606
1607 private void ChildSetGeom(OdePrim odePrim)
1608 {
1609 //if (m_isphysical && Body != IntPtr.Zero)
1610 lock (childrenPrim)
1611 {
1612 foreach (OdePrim prm in childrenPrim)
1613 {
1614 //prm.childPrim = true;
1615 prm.disableBody();
1616 //prm.m_taintparent = null;
1617 //prm._parent = null;
1618 //prm.m_taintPhysics = false;
1619 //prm.m_disabled = true;
1620 //prm.childPrim = false;
1621 }
1622 }
1623 disableBody();
1624
1625
1626 if (Body != IntPtr.Zero)
1627 {
1628 _parent_scene.remActivePrim(this);
1629 }
1630
1631 lock (childrenPrim)
1632 {
1633 foreach (OdePrim prm in childrenPrim)
1634 {
1635 ParentPrim(prm);
1636 }
1637 }
1638
1639 }
1640
1641 private void ChildDelink(OdePrim odePrim)
1642 {
1643 // Okay, we have a delinked child.. need to rebuild the body.
1644 lock (childrenPrim)
1645 {
1646 foreach (OdePrim prm in childrenPrim)
1647 {
1648 prm.childPrim = true;
1649 prm.disableBody();
1650 //prm.m_taintparent = null;
1651 //prm._parent = null;
1652 //prm.m_taintPhysics = false;
1653 //prm.m_disabled = true;
1654 //prm.childPrim = false;
1655 }
1656 }
1657 disableBody();
1658
1659 lock (childrenPrim)
1660 {
1661 childrenPrim.Remove(odePrim);
1662 }
1663
1664 if (Body != IntPtr.Zero)
1665 {
1666 _parent_scene.remActivePrim(this);
1667 }
1668
1669 lock (childrenPrim)
1670 {
1671 foreach (OdePrim prm in childrenPrim)
1672 {
1673 ParentPrim(prm);
1674 }
1675 }
1676 }
1677
1678 private void changeSelectedStatus(float timestep)
1679 {
1680 if (m_taintselected)
1681 {
1682 m_collisionCategories = CollisionCategories.Selected;
1683 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1684
1685 // We do the body disable soft twice because 'in theory' a collision could have happened
1686 // in between the disabling and the collision properties setting
1687 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1688 // through the ground.
1689
1690 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1691 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1692 // so that causes the selected part to wake up and continue moving.
1693
1694 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1695 // assembly will stop simulating during the selection, because of the lack of atomicity
1696 // of select operations (their processing could be interrupted by a thread switch, causing
1697 // simulation to continue before all of the selected object notifications trickle down to
1698 // the physics engine).
1699
1700 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1701 // selected and disabled. then, due to a thread switch, the selection processing is
1702 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1703 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1704 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1705 // up, start simulating again, which in turn wakes up the last 50.
1706
1707 if (m_isphysical)
1708 {
1709 disableBodySoft();
1710 }
1711
1712 if (prim_geom != IntPtr.Zero)
1713 {
1714 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1715 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1716 }
1717
1718 if (m_isphysical)
1719 {
1720 disableBodySoft();
1721 }
1722 if (Body != IntPtr.Zero)
1723 {
1724 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1725 d.BodySetForce(Body, 0f, 0f, 0f);
1726 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1727 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1728 }
1729
1730 }
1731 else
1732 {
1733 m_collisionCategories = CollisionCategories.Geom;
1734
1735 if (m_isphysical)
1736 m_collisionCategories |= CollisionCategories.Body;
1737
1738 m_collisionFlags = m_default_collisionFlags;
1739
1740 if (m_collidesLand)
1741 m_collisionFlags |= CollisionCategories.Land;
1742 if (m_collidesWater)
1743 m_collisionFlags |= CollisionCategories.Water;
1744
1745 if (prim_geom != IntPtr.Zero)
1746 {
1747 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1748 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1749 }
1750 if (Body != IntPtr.Zero)
1751 {
1752 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1753 d.BodySetForce(Body, 0f, 0f, 0f);
1754 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1755 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1756 }
1757
1758 if (m_isphysical)
1759 {
1760 if (Body != IntPtr.Zero)
1761 {
1762 enableBodySoft();
1763 }
1764 }
1765 }
1766
1767 resetCollisionAccounting();
1768 m_isSelected = m_taintselected;
1769 }//end changeSelectedStatus
1770
1771 public void ResetTaints()
1772 {
1773 m_taintposition = _position;
1774 m_taintrot = _orientation;
1775 m_taintPhysics = m_isphysical;
1776 m_taintselected = m_isSelected;
1777 m_taintsize = _size;
1778 m_taintshape = false;
1779 m_taintforce = false;
1780 m_taintdisable = false;
1781 m_taintVelocity = Vector3.Zero;
1782 }
1783
1784 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1785 {
1786 if (_mesh != null) // Special - make mesh
1787 {
1788 setMesh(_parent_scene, _mesh);
1789 }
1790 else // not a mesh
1791 {
1792 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1793 {
1794 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1795 {
1796 if (((_size.X / 2f) > 0f)) // Has size
1797 {
1798 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1799 try
1800 {
1801 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1802 }
1803 catch (AccessViolationException)
1804 {
1805 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1806 ode.dunlock(_parent_scene.world);
1807 return;
1808 }
1809 }
1810 else
1811 {
1812 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1813 try
1814 {
1815 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1816 }
1817 catch (AccessViolationException)
1818 {
1819 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1820 ode.dunlock(_parent_scene.world);
1821 return;
1822 }
1823 }
1824 }
1825 else // not equi-size
1826 {
1827 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1828 try
1829 {
1830 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1831 }
1832 catch (AccessViolationException)
1833 {
1834 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1835 ode.dunlock(_parent_scene.world);
1836 return;
1837 }
1838 }
1839 }
1840
1841 else // not special profile
1842 {
1843 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1844 try
1845 {
1846 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1847 }
1848 catch (AccessViolationException)
1849 {
1850 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1851 ode.dunlock(_parent_scene.world);
1852 return;
1853 }
1854 }
1855 }
1856 }
1857
1858 public void changeadd(float timestep)
1859 {
1860 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1861 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1862
1863 if (targetspace == IntPtr.Zero)
1864 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1865
1866 m_targetSpace = targetspace;
1867
1868 if (_mesh == null && m_meshfailed == false)
1869 {
1870 if (_parent_scene.needsMeshing(_pbs))
1871 {
1872 // Don't need to re-enable body.. it's done in SetMesh
1873 try
1874 {
1875 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1876 }
1877 catch
1878 {
1879 //Don't continuously try to mesh prims when meshing has failed
1880 m_meshfailed = true;
1881 }
1882 // createmesh returns null when it's a shape that isn't a cube.
1883 // m_log.Debug(m_localID);
1884 }
1885 }
1886
1887
1888 lock (_parent_scene.OdeLock)
1889 {
1890 CreateGeom(m_targetSpace, _mesh);
1891
1892 if (prim_geom != IntPtr.Zero)
1893 {
1894 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1895 d.Quaternion myrot = new d.Quaternion();
1896 myrot.X = _orientation.X;
1897 myrot.Y = _orientation.Y;
1898 myrot.Z = _orientation.Z;
1899 myrot.W = _orientation.W;
1900 d.GeomSetQuaternion(prim_geom, ref myrot);
1901 }
1902
1903 if (m_isphysical && Body == IntPtr.Zero)
1904 {
1905 enableBody();
1906 }
1907 }
1908
1909 changeSelectedStatus(timestep);
1910
1911 m_taintadd = false;
1912 }
1913
1914 public void changemove(float timestep)
1915 {
1916 if (m_isphysical)
1917 {
1918// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1919 if (!m_taintremove && !childPrim)
1920 {
1921 if (Body == IntPtr.Zero)
1922 enableBody();
1923 //Prim auto disable after 20 frames,
1924 //if you move it, re-enable the prim manually.
1925 if (_parent != null)
1926 {
1927 if (m_linkJoint != IntPtr.Zero)
1928 {
1929 d.JointDestroy(m_linkJoint);
1930 m_linkJoint = IntPtr.Zero;
1931 }
1932 }
1933 if (Body != IntPtr.Zero)
1934 {
1935 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1936
1937 if (_parent != null)
1938 {
1939 OdePrim odParent = (OdePrim)_parent;
1940 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1941 {
1942// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1943Console.WriteLine("ODEPrim JointCreateFixed !!!");
1944 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1945 d.JointAttach(m_linkJoint, Body, odParent.Body);
1946 d.JointSetFixed(m_linkJoint);
1947 }
1948 }
1949 d.BodyEnable(Body);
1950 if (m_type != Vehicle.TYPE_NONE)
1951 {
1952 Enable(Body, _parent_scene);
1953 }
1954 }
1955 else
1956 {
1957 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1958 }
1959 }
1960 //else
1961 // {
1962 //m_log.Debug("[BUG]: race!");
1963 //}
1964 }
1965 else
1966 {
1967 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1968 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1969 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1970
1971 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1972 m_targetSpace = tempspace;
1973
1974 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1975 if (prim_geom != IntPtr.Zero)
1976 {
1977 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1978
1979 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1980 d.SpaceAdd(m_targetSpace, prim_geom);
1981 }
1982 }
1983
1984 changeSelectedStatus(timestep);
1985
1986 resetCollisionAccounting();
1987 m_taintposition = _position;
1988 }
1989
1990
1991
1992 public void rotate(float timestep)
1993 {
1994 d.Quaternion myrot = new d.Quaternion();
1995 myrot.X = _orientation.X;
1996 myrot.Y = _orientation.Y;
1997 myrot.Z = _orientation.Z;
1998 myrot.W = _orientation.W;
1999 if (Body != IntPtr.Zero)
2000 {
2001 // KF: If this is a root prim do BodySet
2002 d.BodySetQuaternion(Body, ref myrot);
2003 }
2004 else
2005 {
2006 // daughter prim, do Geom set
2007 d.GeomSetQuaternion(prim_geom, ref myrot);
2008 }
2009
2010 resetCollisionAccounting();
2011 m_taintrot = _orientation;
2012 }
2013
2014 private void resetCollisionAccounting()
2015 {
2016 m_collisionscore = 0;
2017 m_interpenetrationcount = 0;
2018 m_disabled = false;
2019 }
2020
2021 public void changedisable(float timestep)
2022 {
2023 m_disabled = true;
2024 if (Body != IntPtr.Zero)
2025 {
2026 d.BodyDisable(Body);
2027 Body = IntPtr.Zero;
2028 }
2029
2030 m_taintdisable = false;
2031 }
2032
2033 public void changePhysicsStatus(float timestep)
2034 {
2035 if (m_isphysical == true)
2036 {
2037 if (Body == IntPtr.Zero)
2038 {
2039 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2040 {
2041 changeshape(2f);
2042 }
2043 else
2044 {
2045 enableBody();
2046 }
2047 }
2048 }
2049 else
2050 {
2051 if (Body != IntPtr.Zero)
2052 {
2053 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2054 {
2055 _mesh = null;
2056 changeadd(2f);
2057 }
2058 if (childPrim)
2059 {
2060 if (_parent != null)
2061 {
2062 OdePrim parent = (OdePrim)_parent;
2063 parent.ChildDelink(this);
2064 }
2065 }
2066 else
2067 {
2068 disableBody();
2069 }
2070 }
2071 }
2072
2073 changeSelectedStatus(timestep);
2074
2075 resetCollisionAccounting();
2076 m_taintPhysics = m_isphysical;
2077 }
2078
2079 public void changesize(float timestamp)
2080 {
2081
2082 string oldname = _parent_scene.geom_name_map[prim_geom];
2083
2084 if (_size.X <= 0) _size.X = 0.01f;
2085 if (_size.Y <= 0) _size.Y = 0.01f;
2086 if (_size.Z <= 0) _size.Z = 0.01f;
2087
2088 // Cleanup of old prim geometry
2089 if (_mesh != null)
2090 {
2091 // Cleanup meshing here
2092 }
2093 //kill body to rebuild
2094 if (IsPhysical && Body != IntPtr.Zero)
2095 {
2096 if (childPrim)
2097 {
2098 if (_parent != null)
2099 {
2100 OdePrim parent = (OdePrim)_parent;
2101 parent.ChildDelink(this);
2102 }
2103 }
2104 else
2105 {
2106 disableBody();
2107 }
2108 }
2109 if (d.SpaceQuery(m_targetSpace, prim_geom))
2110 {
2111 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2112 d.SpaceRemove(m_targetSpace, prim_geom);
2113 }
2114 // we don't need to do space calculation because the client sends a position update also.
2115
2116 // Construction of new prim
2117 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2118 {
2119 float meshlod = _parent_scene.meshSculptLOD;
2120
2121 if (IsPhysical)
2122 meshlod = _parent_scene.MeshSculptphysicalLOD;
2123 // Don't need to re-enable body.. it's done in SetMesh
2124
2125 IMesh mesh = null;
2126
2127 try
2128 {
2129 if (_parent_scene.needsMeshing(_pbs))
2130 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2131 }
2132 catch
2133 {
2134 m_meshfailed = true;
2135 }
2136
2137 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2138 CreateGeom(m_targetSpace, mesh);
2139
2140
2141 }
2142 else
2143 {
2144 _mesh = null;
2145 CreateGeom(m_targetSpace, _mesh);
2146 }
2147
2148 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2149 d.Quaternion myrot = new d.Quaternion();
2150 myrot.X = _orientation.X;
2151 myrot.Y = _orientation.Y;
2152 myrot.Z = _orientation.Z;
2153 myrot.W = _orientation.W;
2154 d.GeomSetQuaternion(prim_geom, ref myrot);
2155
2156 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2157 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2158 {
2159 // Re creates body on size.
2160 // EnableBody also does setMass()
2161 enableBody();
2162 d.BodyEnable(Body);
2163 }
2164
2165 _parent_scene.geom_name_map[prim_geom] = oldname;
2166
2167 changeSelectedStatus(timestamp);
2168 if (childPrim)
2169 {
2170 if (_parent is OdePrim)
2171 {
2172 OdePrim parent = (OdePrim)_parent;
2173 parent.ChildSetGeom(this);
2174 }
2175 }
2176 resetCollisionAccounting();
2177 m_taintsize = _size;
2178 }
2179
2180
2181
2182 public void changefloatonwater(float timestep)
2183 {
2184 m_collidesWater = m_taintCollidesWater;
2185
2186 if (prim_geom != IntPtr.Zero)
2187 {
2188 if (m_collidesWater)
2189 {
2190 m_collisionFlags |= CollisionCategories.Water;
2191 }
2192 else
2193 {
2194 m_collisionFlags &= ~CollisionCategories.Water;
2195 }
2196 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2197 }
2198 }
2199
2200 public void changeshape(float timestamp)
2201 {
2202 string oldname = _parent_scene.geom_name_map[prim_geom];
2203
2204 // Cleanup of old prim geometry and Bodies
2205 if (IsPhysical && Body != IntPtr.Zero)
2206 {
2207 if (childPrim)
2208 {
2209 if (_parent != null)
2210 {
2211 OdePrim parent = (OdePrim)_parent;
2212 parent.ChildDelink(this);
2213 }
2214 }
2215 else
2216 {
2217 disableBody();
2218 }
2219 }
2220
2221
2222 // we don't need to do space calculation because the client sends a position update also.
2223 if (_size.X <= 0) _size.X = 0.01f;
2224 if (_size.Y <= 0) _size.Y = 0.01f;
2225 if (_size.Z <= 0) _size.Z = 0.01f;
2226 // Construction of new prim
2227
2228 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2229 {
2230 // Don't need to re-enable body.. it's done in SetMesh
2231 float meshlod = _parent_scene.meshSculptLOD;
2232
2233 if (IsPhysical)
2234 meshlod = _parent_scene.MeshSculptphysicalLOD;
2235 try
2236 {
2237 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2238 CreateGeom(m_targetSpace, mesh);
2239 }
2240 catch
2241 {
2242 m_meshfailed = true;
2243 }
2244 // createmesh returns null when it doesn't mesh.
2245 }
2246 else
2247 {
2248 _mesh = null;
2249 CreateGeom(m_targetSpace, null);
2250 }
2251
2252 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2253 d.Quaternion myrot = new d.Quaternion();
2254 //myrot.W = _orientation.w;
2255 myrot.W = _orientation.W;
2256 myrot.X = _orientation.X;
2257 myrot.Y = _orientation.Y;
2258 myrot.Z = _orientation.Z;
2259 d.GeomSetQuaternion(prim_geom, ref myrot);
2260
2261 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2262 if (IsPhysical && Body == IntPtr.Zero)
2263 {
2264 // Re creates body on size.
2265 // EnableBody also does setMass()
2266 enableBody();
2267 if (Body != IntPtr.Zero)
2268 {
2269 d.BodyEnable(Body);
2270 }
2271 }
2272 _parent_scene.geom_name_map[prim_geom] = oldname;
2273
2274 changeSelectedStatus(timestamp);
2275 if (childPrim)
2276 {
2277 if (_parent is OdePrim)
2278 {
2279 OdePrim parent = (OdePrim)_parent;
2280 parent.ChildSetGeom(this);
2281 }
2282 }
2283 resetCollisionAccounting();
2284 m_taintshape = false;
2285 }
2286
2287 public void changeAddForce(float timestamp)
2288 {
2289 if (!m_isSelected)
2290 {
2291 lock (m_forcelist)
2292 {
2293 //m_log.Info("[PHYSICS]: dequeing forcelist");
2294 if (IsPhysical)
2295 {
2296 Vector3 iforce = Vector3.Zero;
2297 int i = 0;
2298 try
2299 {
2300 for (i = 0; i < m_forcelist.Count; i++)
2301 {
2302
2303 iforce = iforce + (m_forcelist[i] * 100);
2304 }
2305 }
2306 catch (IndexOutOfRangeException)
2307 {
2308 m_forcelist = new List<Vector3>();
2309 m_collisionscore = 0;
2310 m_interpenetrationcount = 0;
2311 m_taintforce = false;
2312 return;
2313 }
2314 catch (ArgumentOutOfRangeException)
2315 {
2316 m_forcelist = new List<Vector3>();
2317 m_collisionscore = 0;
2318 m_interpenetrationcount = 0;
2319 m_taintforce = false;
2320 return;
2321 }
2322 d.BodyEnable(Body);
2323
2324 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2325 }
2326 m_forcelist.Clear();
2327 }
2328
2329 m_collisionscore = 0;
2330 m_interpenetrationcount = 0;
2331 }
2332
2333 m_taintforce = false;
2334
2335 }
2336
2337
2338
2339 public void changeSetTorque(float timestamp)
2340 {
2341 if (!m_isSelected)
2342 {
2343 if (IsPhysical && Body != IntPtr.Zero)
2344 {
2345 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2346 }
2347 }
2348
2349 m_taintTorque = Vector3.Zero;
2350 }
2351
2352 public void changeAddAngularForce(float timestamp)
2353 {
2354 if (!m_isSelected)
2355 {
2356 lock (m_angularforcelist)
2357 {
2358 //m_log.Info("[PHYSICS]: dequeing forcelist");
2359 if (IsPhysical)
2360 {
2361 Vector3 iforce = Vector3.Zero;
2362 for (int i = 0; i < m_angularforcelist.Count; i++)
2363 {
2364 iforce = iforce + (m_angularforcelist[i] * 100);
2365 }
2366 d.BodyEnable(Body);
2367 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2368
2369 }
2370 m_angularforcelist.Clear();
2371 }
2372
2373 m_collisionscore = 0;
2374 m_interpenetrationcount = 0;
2375 }
2376
2377 m_taintaddangularforce = false;
2378 }
2379
2380 private void changevelocity(float timestep)
2381 {
2382 if (!m_isSelected)
2383 {
2384 Thread.Sleep(20);
2385 if (IsPhysical)
2386 {
2387 if (Body != IntPtr.Zero)
2388 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2389 }
2390
2391 //resetCollisionAccounting();
2392 }
2393 m_taintVelocity = Vector3.Zero;
2394 }
2395
2396 public void UpdatePositionAndVelocity()
2397 {
2398 return; // moved to the Move () method
2399 }
2400
2401 public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
2402 {
2403 obj.I.M00 = pMat[0, 0];
2404 obj.I.M01 = pMat[0, 1];
2405 obj.I.M02 = pMat[0, 2];
2406 obj.I.M10 = pMat[1, 0];
2407 obj.I.M11 = pMat[1, 1];
2408 obj.I.M12 = pMat[1, 2];
2409 obj.I.M20 = pMat[2, 0];
2410 obj.I.M21 = pMat[2, 1];
2411 obj.I.M22 = pMat[2, 2];
2412 return obj;
2413 }
2414
2415 public override void SubscribeEvents(int ms)
2416 {
2417 m_eventsubscription = ms;
2418 _parent_scene.addCollisionEventReporting(this);
2419 }
2420
2421 public override void UnSubscribeEvents()
2422 {
2423 _parent_scene.remCollisionEventReporting(this);
2424 m_eventsubscription = 0;
2425 }
2426
2427 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
2428 {
2429 if (CollisionEventsThisFrame == null)
2430 CollisionEventsThisFrame = new CollisionEventUpdate();
2431 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
2432 }
2433
2434 public void SendCollisions()
2435 {
2436 if (CollisionEventsThisFrame == null)
2437 return;
2438
2439 base.SendCollisionUpdate(CollisionEventsThisFrame);
2440
2441 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
2442 CollisionEventsThisFrame = null;
2443 else
2444 CollisionEventsThisFrame = new CollisionEventUpdate();
2445 }
2446
2447 public override bool SubscribedEvents()
2448 {
2449 if (m_eventsubscription > 0)
2450 return true;
2451 return false;
2452 }
2453
2454 public static Matrix4 Inverse(Matrix4 pMat)
2455 {
2456 if (determinant3x3(pMat) == 0)
2457 {
2458 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
2459 }
2460
2461
2462
2463 return (Adjoint(pMat) / determinant3x3(pMat));
2464 }
2465
2466 public static Matrix4 Adjoint(Matrix4 pMat)
2467 {
2468 Matrix4 adjointMatrix = new Matrix4();
2469 for (int i=0; i<4; i++)
2470 {
2471 for (int j=0; j<4; j++)
2472 {
2473 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
2474 }
2475 }
2476
2477 adjointMatrix = Transpose(adjointMatrix);
2478 return adjointMatrix;
2479 }
2480
2481 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
2482 {
2483 Matrix4 minor = new Matrix4();
2484 int m = 0, n = 0;
2485 for (int i = 0; i < 4; i++)
2486 {
2487 if (i == iRow)
2488 continue;
2489 n = 0;
2490 for (int j = 0; j < 4; j++)
2491 {
2492 if (j == iCol)
2493 continue;
2494 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
2495 n++;
2496 }
2497 m++;
2498 }
2499 return minor;
2500 }
2501
2502 public static Matrix4 Transpose(Matrix4 pMat)
2503 {
2504 Matrix4 transposeMatrix = new Matrix4();
2505 for (int i = 0; i < 4; i++)
2506 for (int j = 0; j < 4; j++)
2507 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
2508 return transposeMatrix;
2509 }
2510
2511 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
2512 {
2513 switch (r)
2514 {
2515 case 0:
2516 switch (c)
2517 {
2518 case 0:
2519 pMat.M11 = val;
2520 break;
2521 case 1:
2522 pMat.M12 = val;
2523 break;
2524 case 2:
2525 pMat.M13 = val;
2526 break;
2527 case 3:
2528 pMat.M14 = val;
2529 break;
2530 }
2531
2532 break;
2533 case 1:
2534 switch (c)
2535 {
2536 case 0:
2537 pMat.M21 = val;
2538 break;
2539 case 1:
2540 pMat.M22 = val;
2541 break;
2542 case 2:
2543 pMat.M23 = val;
2544 break;
2545 case 3:
2546 pMat.M24 = val;
2547 break;
2548 }
2549
2550 break;
2551 case 2:
2552 switch (c)
2553 {
2554 case 0:
2555 pMat.M31 = val;
2556 break;
2557 case 1:
2558 pMat.M32 = val;
2559 break;
2560 case 2:
2561 pMat.M33 = val;
2562 break;
2563 case 3:
2564 pMat.M34 = val;
2565 break;
2566 }
2567
2568 break;
2569 case 3:
2570 switch (c)
2571 {
2572 case 0:
2573 pMat.M41 = val;
2574 break;
2575 case 1:
2576 pMat.M42 = val;
2577 break;
2578 case 2:
2579 pMat.M43 = val;
2580 break;
2581 case 3:
2582 pMat.M44 = val;
2583 break;
2584 }
2585
2586 break;
2587 }
2588 }
2589 private static float determinant3x3(Matrix4 pMat)
2590 {
2591 float det = 0;
2592 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
2593 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
2594 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
2595 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
2596 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
2597 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
2598
2599 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
2600 return det;
2601
2602 }
2603
2604 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
2605 {
2606 dst.c.W = src.c.W;
2607 dst.c.X = src.c.X;
2608 dst.c.Y = src.c.Y;
2609 dst.c.Z = src.c.Z;
2610 dst.mass = src.mass;
2611 dst.I.M00 = src.I.M00;
2612 dst.I.M01 = src.I.M01;
2613 dst.I.M02 = src.I.M02;
2614 dst.I.M10 = src.I.M10;
2615 dst.I.M11 = src.I.M11;
2616 dst.I.M12 = src.I.M12;
2617 dst.I.M20 = src.I.M20;
2618 dst.I.M21 = src.I.M21;
2619 dst.I.M22 = src.I.M22;
2620 }
2621
2622 public override void SetMaterial(int pMaterial)
2623 {
2624 m_material = pMaterial;
2625 }
2626
2627 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
2628 {
2629 switch (pParam)
2630 {
2631 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
2632 if (pValue < 0.01f) pValue = 0.01f;
2633 // m_angularDeflectionEfficiency = pValue;
2634 break;
2635 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
2636 if (pValue < 0.1f) pValue = 0.1f;
2637 // m_angularDeflectionTimescale = pValue;
2638 break;
2639 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
2640 if (pValue < 0.3f) pValue = 0.3f;
2641 m_angularMotorDecayTimescale = pValue;
2642 break;
2643 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
2644 if (pValue < 0.3f) pValue = 0.3f;
2645 m_angularMotorTimescale = pValue;
2646 break;
2647 case Vehicle.BANKING_EFFICIENCY:
2648 if (pValue < 0.01f) pValue = 0.01f;
2649 // m_bankingEfficiency = pValue;
2650 break;
2651 case Vehicle.BANKING_MIX:
2652 if (pValue < 0.01f) pValue = 0.01f;
2653 // m_bankingMix = pValue;
2654 break;
2655 case Vehicle.BANKING_TIMESCALE:
2656 if (pValue < 0.01f) pValue = 0.01f;
2657 // m_bankingTimescale = pValue;
2658 break;
2659 case Vehicle.BUOYANCY:
2660 if (pValue < -1f) pValue = -1f;
2661 if (pValue > 1f) pValue = 1f;
2662 m_VehicleBuoyancy = pValue;
2663 break;
2664// case Vehicle.HOVER_EFFICIENCY:
2665// if (pValue < 0f) pValue = 0f;
2666// if (pValue > 1f) pValue = 1f;
2667// m_VhoverEfficiency = pValue;
2668// break;
2669 case Vehicle.HOVER_HEIGHT:
2670 m_VhoverHeight = pValue;
2671 break;
2672 case Vehicle.HOVER_TIMESCALE:
2673 if (pValue < 0.1f) pValue = 0.1f;
2674 m_VhoverTimescale = pValue;
2675 break;
2676 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
2677 if (pValue < 0.01f) pValue = 0.01f;
2678 // m_linearDeflectionEfficiency = pValue;
2679 break;
2680 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
2681 if (pValue < 0.01f) pValue = 0.01f;
2682 // m_linearDeflectionTimescale = pValue;
2683 break;
2684 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
2685 if (pValue < 0.3f) pValue = 0.3f;
2686 m_linearMotorDecayTimescale = pValue;
2687 break;
2688 case Vehicle.LINEAR_MOTOR_TIMESCALE:
2689 if (pValue < 0.1f) pValue = 0.1f;
2690 m_linearMotorTimescale = pValue;
2691 break;
2692 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
2693 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
2694 if (pValue > 1.0f) pValue = 1.0f;
2695 m_verticalAttractionEfficiency = pValue;
2696 break;
2697 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
2698 if (pValue < 0.1f) pValue = 0.1f;
2699 m_verticalAttractionTimescale = pValue;
2700 break;
2701
2702 // These are vector properties but the engine lets you use a single float value to
2703 // set all of the components to the same value
2704 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2705 if (pValue > 30f) pValue = 30f;
2706 if (pValue < 0.1f) pValue = 0.1f;
2707 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
2708 break;
2709 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2710 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
2711 UpdateAngDecay();
2712 break;
2713 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2714 if (pValue < 0.1f) pValue = 0.1f;
2715 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
2716 break;
2717 case Vehicle.LINEAR_MOTOR_DIRECTION:
2718 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
2719 UpdateLinDecay();
2720 break;
2721 case Vehicle.LINEAR_MOTOR_OFFSET:
2722 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
2723 break;
2724
2725 }
2726
2727 }//end ProcessFloatVehicleParam
2728
2729 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
2730 {
2731 switch (pParam)
2732 {
2733 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2734 if (pValue.X > 30f) pValue.X = 30f;
2735 if (pValue.X < 0.1f) pValue.X = 0.1f;
2736 if (pValue.Y > 30f) pValue.Y = 30f;
2737 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2738 if (pValue.Z > 30f) pValue.Z = 30f;
2739 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2740 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2741 break;
2742 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2743 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
2744 // Limit requested angular speed to 2 rps= 4 pi rads/sec
2745 if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
2746 if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
2747 if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
2748 if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
2749 if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
2750 if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
2751 UpdateAngDecay();
2752 break;
2753 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2754 if (pValue.X < 0.1f) pValue.X = 0.1f;
2755 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2756 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2757 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2758 break;
2759 case Vehicle.LINEAR_MOTOR_DIRECTION:
2760 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting
2761 UpdateLinDecay();
2762 break;
2763 case Vehicle.LINEAR_MOTOR_OFFSET:
2764 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
2765 break;
2766 }
2767
2768 }//end ProcessVectorVehicleParam
2769
2770 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
2771 {
2772 switch (pParam)
2773 {
2774 case Vehicle.REFERENCE_FRAME:
2775 // m_referenceFrame = pValue;
2776 break;
2777 }
2778
2779 }//end ProcessRotationVehicleParam
2780
2781 internal void ProcessVehicleFlags(int pParam, bool remove)
2782 {
2783 if (remove)
2784 {
2785 m_flags &= ~((VehicleFlag)pParam);
2786 }
2787 else
2788 {
2789 m_flags |= (VehicleFlag)pParam;
2790 }
2791 }
2792
2793 internal void ProcessTypeChange(Vehicle pType)
2794 {
2795 // Set Defaults For Type
2796 m_type = pType;
2797 switch (pType)
2798 {
2799 case Vehicle.TYPE_SLED:
2800 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
2801 m_angularFrictionTimescale = new Vector3(30, 30, 30);
2802// m_lLinMotorVel = Vector3.Zero;
2803 m_linearMotorTimescale = 1000;
2804 m_linearMotorDecayTimescale = 120;
2805 m_angularMotorDirection = Vector3.Zero;
2806 m_angularMotorDVel = Vector3.Zero;
2807 m_angularMotorTimescale = 1000;
2808 m_angularMotorDecayTimescale = 120;
2809 m_VhoverHeight = 0;
2810// m_VhoverEfficiency = 1;
2811 m_VhoverTimescale = 10;
2812 m_VehicleBuoyancy = 0;
2813 // m_linearDeflectionEfficiency = 1;
2814 // m_linearDeflectionTimescale = 1;
2815 // m_angularDeflectionEfficiency = 1;
2816 // m_angularDeflectionTimescale = 1000;
2817 // m_bankingEfficiency = 0;
2818 // m_bankingMix = 1;
2819 // m_bankingTimescale = 10;
2820 // m_referenceFrame = Quaternion.Identity;
2821 m_flags &=
2822 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2823 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2824 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2825 break;
2826 case Vehicle.TYPE_CAR:
2827 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
2828 m_angularFrictionTimescale = new Vector3(30, 30, 30); // was 1000, but sl max frict time is 30.
2829// m_lLinMotorVel = Vector3.Zero;
2830 m_linearMotorTimescale = 1;
2831 m_linearMotorDecayTimescale = 60;
2832 m_angularMotorDirection = Vector3.Zero;
2833 m_angularMotorDVel = Vector3.Zero;
2834 m_angularMotorTimescale = 1;
2835 m_angularMotorDecayTimescale = 0.8f;
2836 m_VhoverHeight = 0;
2837// m_VhoverEfficiency = 0;
2838 m_VhoverTimescale = 1000;
2839 m_VehicleBuoyancy = 0;
2840 // // m_linearDeflectionEfficiency = 1;
2841 // // m_linearDeflectionTimescale = 2;
2842 // // m_angularDeflectionEfficiency = 0;
2843 // m_angularDeflectionTimescale = 10;
2844 m_verticalAttractionEfficiency = 1f;
2845 m_verticalAttractionTimescale = 10f;
2846 // m_bankingEfficiency = -0.2f;
2847 // m_bankingMix = 1;
2848 // m_bankingTimescale = 1;
2849 // m_referenceFrame = Quaternion.Identity;
2850 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2851 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
2852 VehicleFlag.LIMIT_MOTOR_UP);
2853 break;
2854 case Vehicle.TYPE_BOAT:
2855 m_linearFrictionTimescale = new Vector3(10, 3, 2);
2856 m_angularFrictionTimescale = new Vector3(10,10,10);
2857// m_lLinMotorVel = Vector3.Zero;
2858 m_linearMotorTimescale = 5;
2859 m_linearMotorDecayTimescale = 60;
2860 m_angularMotorDirection = Vector3.Zero;
2861 m_angularMotorDVel = Vector3.Zero;
2862 m_angularMotorTimescale = 4;
2863 m_angularMotorDecayTimescale = 4;
2864 m_VhoverHeight = 0;
2865// m_VhoverEfficiency = 0.5f;
2866 m_VhoverTimescale = 2;
2867 m_VehicleBuoyancy = 1;
2868 // m_linearDeflectionEfficiency = 0.5f;
2869 // m_linearDeflectionTimescale = 3;
2870 // m_angularDeflectionEfficiency = 0.5f;
2871 // m_angularDeflectionTimescale = 5;
2872 m_verticalAttractionEfficiency = 0.5f;
2873 m_verticalAttractionTimescale = 5f;
2874 // m_bankingEfficiency = -0.3f;
2875 // m_bankingMix = 0.8f;
2876 // m_bankingTimescale = 1;
2877 // m_referenceFrame = Quaternion.Identity;
2878 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
2879 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2880 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
2881 VehicleFlag.LIMIT_MOTOR_UP);
2882 break;
2883 case Vehicle.TYPE_AIRPLANE:
2884 m_linearFrictionTimescale = new Vector3(200, 10, 5);
2885 m_angularFrictionTimescale = new Vector3(20, 20, 20);
2886// m_lLinMotorVel = Vector3.Zero;
2887 m_linearMotorTimescale = 2;
2888 m_linearMotorDecayTimescale = 60;
2889 m_angularMotorDirection = Vector3.Zero;
2890 m_angularMotorDVel = Vector3.Zero;
2891 m_angularMotorTimescale = 4;
2892 m_angularMotorDecayTimescale = 4;
2893 m_VhoverHeight = 0;
2894// m_VhoverEfficiency = 0.5f;
2895 m_VhoverTimescale = 1000;
2896 m_VehicleBuoyancy = 0;
2897 // m_linearDeflectionEfficiency = 0.5f;
2898 // m_linearDeflectionTimescale = 3;
2899 // m_angularDeflectionEfficiency = 1;
2900 // m_angularDeflectionTimescale = 2;
2901 m_verticalAttractionEfficiency = 0.9f;
2902 m_verticalAttractionTimescale = 2f;
2903 // m_bankingEfficiency = 1;
2904 // m_bankingMix = 0.7f;
2905 // m_bankingTimescale = 2;
2906 // m_referenceFrame = Quaternion.Identity;
2907 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2908 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2909 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
2910 break;
2911 case Vehicle.TYPE_BALLOON:
2912 m_linearFrictionTimescale = new Vector3(5, 5, 5);
2913 m_angularFrictionTimescale = new Vector3(10, 10, 10);
2914 m_linearMotorTimescale = 5;
2915 m_linearMotorDecayTimescale = 60;
2916 m_angularMotorDirection = Vector3.Zero;
2917 m_angularMotorDVel = Vector3.Zero;
2918 m_angularMotorTimescale = 6;
2919 m_angularMotorDecayTimescale = 10;
2920 m_VhoverHeight = 5;
2921// m_VhoverEfficiency = 0.8f;
2922 m_VhoverTimescale = 10;
2923 m_VehicleBuoyancy = 1;
2924 // m_linearDeflectionEfficiency = 0;
2925 // m_linearDeflectionTimescale = 5;
2926 // m_angularDeflectionEfficiency = 0;
2927 // m_angularDeflectionTimescale = 5;
2928 m_verticalAttractionEfficiency = 1f;
2929 m_verticalAttractionTimescale = 100f;
2930 // m_bankingEfficiency = 0;
2931 // m_bankingMix = 0.7f;
2932 // m_bankingTimescale = 5;
2933 // m_referenceFrame = Quaternion.Identity;
2934 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2935 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2936 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2937 break;
2938
2939 }
2940 }//end SetDefaultsForType
2941
2942 internal void Enable(IntPtr pBody, OdeScene pParentScene)
2943 {
2944 if (m_type == Vehicle.TYPE_NONE)
2945 return;
2946
2947 m_body = pBody;
2948 }
2949
2950
2951 internal void Halt()
2952 { // Kill all motions, when non-physical
2953 // m_linearMotorDirection = Vector3.Zero;
2954 m_lLinMotorDVel = Vector3.Zero;
2955 m_lLinObjectVel = Vector3.Zero;
2956 m_wLinObjectVel = Vector3.Zero;
2957 m_angularMotorDirection = Vector3.Zero;
2958 m_lastAngularVelocity = Vector3.Zero;
2959 m_angularMotorDVel = Vector3.Zero;
2960 _acceleration = Vector3.Zero;
2961 }
2962
2963 private void UpdateLinDecay()
2964 {
2965// if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X;
2966// if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2967// if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2968 m_lLinMotorDVel.X = m_linearMotorDirection.X;
2969 m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2970 m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2971 } // else let the motor decay on its own
2972
2973 private void UpdateAngDecay()
2974 {
2975// if (Math.Abs(m_angularMotorDirection.X) > Math.Abs(m_angularMotorDVel.X)) m_angularMotorDVel.X = m_angularMotorDirection.X;
2976// if (Math.Abs(m_angularMotorDirection.Y) > Math.Abs(m_angularMotorDVel.Y)) m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2977// if (Math.Abs(m_angularMotorDirection.Z) > Math.Abs(m_angularMotorDVel.Z)) m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2978 m_angularMotorDVel.X = m_angularMotorDirection.X;
2979 m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2980 m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2981 } // else let the motor decay on its own
2982
2983 public void Move(float timestep)
2984 {
2985 float fx = 0;
2986 float fy = 0;
2987 float fz = 0;
2988 Vector3 linvel; // velocity applied, including any reversal
2989 int outside = 0;
2990
2991 // If geomCrossingFailuresBeforeOutofbounds is set to 0 in OpenSim.ini then phys objects bounce off region borders.
2992 // This is a temp patch until proper region crossing is developed.
2993
2994 int failureLimit = _parent_scene.geomCrossingFailuresBeforeOutofbounds;
2995 float fence = _parent_scene.geomRegionFence;
2996
2997 frcount++; // used to limit debug comment output
2998 if (frcount > 50)
2999 frcount = 0;
3000
3001 if(revcount > 0) revcount--;
3002
3003 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3004 {
3005 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3006 bool lastZeroFlag = _zeroFlag; // was it stopped
3007
3008 d.Vector3 vec = d.BodyGetPosition(Body);
3009 Vector3 l_position = Vector3.Zero;
3010 l_position.X = vec.X;
3011 l_position.Y = vec.Y;
3012 l_position.Z = vec.Z;
3013 m_lastposition = _position;
3014 _position = l_position;
3015
3016 d.Quaternion ori = d.BodyGetQuaternion(Body);
3017 // Quaternion l_orientation = Quaternion.Identity;
3018 _orientation.X = ori.X;
3019 _orientation.Y = ori.Y;
3020 _orientation.Z = ori.Z;
3021 _orientation.W = ori.W;
3022 m_lastorientation = _orientation;
3023
3024 d.Vector3 vel = d.BodyGetLinearVel(Body);
3025 m_lastVelocity = _velocity;
3026 _velocity.X = vel.X;
3027 _velocity.Y = vel.Y;
3028 _velocity.Z = vel.Z;
3029 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3030
3031 d.Vector3 torque = d.BodyGetTorque(Body);
3032 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3033
3034 base.RequestPhysicsterseUpdate();
3035
3036//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3037
3038 // Check if outside region
3039 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3040 if (l_position.X > ((float)_parent_scene.WorldExtents.X - fence))
3041 {
3042 l_position.X = ((float)_parent_scene.WorldExtents.X - fence);
3043 outside = 1;
3044 }
3045
3046 if (l_position.X < fence)
3047 {
3048 l_position.X = fence;
3049 outside = 2;
3050 }
3051 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - fence))
3052 {
3053 l_position.Y = ((float)_parent_scene.WorldExtents.Y - fence);
3054 outside = 3;
3055 }
3056
3057 if (l_position.Y < fence)
3058 {
3059 l_position.Y = fence;
3060 outside = 4;
3061 }
3062
3063 if (outside > 0)
3064 {
3065
3066//Console.WriteLine("Border {0} fence={1}", l_position, fence);
3067 if (fence > 0.0f) // bounce object off boundary
3068 {
3069 if (revcount == 0)
3070 {
3071 if (outside < 3)
3072 {
3073 _velocity.X = -_velocity.X;
3074 }
3075 else
3076 {
3077 _velocity.Y = -_velocity.Y;
3078 }
3079 if (m_type != Vehicle.TYPE_NONE) Halt();
3080 _position = l_position;
3081 m_taintposition = _position;
3082 m_lastVelocity = _velocity;
3083 _acceleration = Vector3.Zero;
3084 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3085 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3086 base.RequestPhysicsterseUpdate();
3087
3088 revcount = 25; // wait for object to move away from border
3089 }
3090 } // else old crossing mode
3091 else if (m_crossingfailures < failureLimit)
3092 { // keep trying to cross?
3093 _position = l_position;
3094 //_parent_scene.remActivePrim(this);
3095 if (_parent == null) base.RequestPhysicsterseUpdate();
3096 return; // Dont process any other motion?
3097 }
3098 else
3099 { // Too many tries
3100 if (_parent == null) base.RaiseOutOfBounds(l_position);
3101 return; // Dont process any other motion?
3102 } // end various methods
3103 } // end outside region horizontally
3104
3105
3106 if (l_position.Z < 0)
3107 {
3108 // This is so prim that get lost underground don't fall forever and suck up
3109 //
3110 // Sim resources and memory.
3111 // Disables the prim's movement physics....
3112 // It's a hack and will generate a console message if it fails.
3113
3114 //IsPhysical = false;
3115 if (_parent == null) base.RaiseOutOfBounds(_position);
3116
3117
3118 _acceleration.X = 0; // This stuff may stop client display but it has no
3119 _acceleration.Y = 0; // effect on the object in phys engine!
3120 _acceleration.Z = 0;
3121
3122 _velocity.X = 0;
3123 _velocity.Y = 0;
3124 _velocity.Z = 0;
3125 m_rotationalVelocity.X = 0;
3126 m_rotationalVelocity.Y = 0;
3127 m_rotationalVelocity.Z = 0;
3128
3129 if (_parent == null) base.RequestPhysicsterseUpdate();
3130
3131 m_throttleUpdates = false;
3132 throttleCounter = 0;
3133 _zeroFlag = true;
3134 //outofBounds = true;
3135 } // end neg Z check
3136
3137 // Is it moving?
3138 /* if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3139 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3140 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) */
3141 if ( (Vector3.Mag(_velocity) < 0.01) && // moving very slowly
3142 (Vector3.Mag(_velocity) < Vector3.Mag(m_lastVelocity)) && // decelerating
3143 (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001) ) // spinning very slowly
3144 {
3145 _zeroFlag = true;
3146 m_throttleUpdates = false;
3147 }
3148 else
3149 {
3150 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3151 _zeroFlag = false;
3152 m_lastUpdateSent = false;
3153 //m_throttleUpdates = false;
3154 }
3155
3156 if (_zeroFlag)
3157 { // Its stopped
3158 _velocity.X = 0.0f;
3159 _velocity.Y = 0.0f;
3160 // _velocity.Z = 0.0f;
3161
3162 _acceleration.X = 0;
3163 _acceleration.Y = 0;
3164 // _acceleration.Z = 0;
3165
3166 m_rotationalVelocity.X = 0;
3167 m_rotationalVelocity.Y = 0;
3168 m_rotationalVelocity.Z = 0;
3169 // Stop it in the phys engine
3170 d.BodySetLinearVel(Body, 0.0f, 0.0f, _velocity.Z);
3171 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3172
3173 if (!m_lastUpdateSent)
3174 {
3175 m_throttleUpdates = false;
3176 throttleCounter = 0;
3177 if (_parent == null)
3178 {
3179 base.RequestPhysicsterseUpdate();
3180 }
3181
3182 m_lastUpdateSent = true;
3183 }
3184 }
3185 else
3186 { // Its moving
3187 if (lastZeroFlag != _zeroFlag)
3188 {
3189 if (_parent == null)
3190 {
3191 base.RequestPhysicsterseUpdate();
3192 }
3193 }
3194 m_lastUpdateSent = false;
3195 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3196 {
3197 if (_parent == null)
3198 {
3199 base.RequestPhysicsterseUpdate();
3200 }
3201 }
3202 else
3203 {
3204 throttleCounter++;
3205 }
3206 }
3207 m_lastposition = l_position;
3208
3209 /// End UpdatePositionAndVelocity insert
3210
3211
3212 // Rotation lock =====================================
3213 if(m_rotateEnableUpdate)
3214 {
3215 // Snapshot current angles, set up Amotor(s)
3216 m_rotateEnableUpdate = false;
3217 m_rotateEnable = m_rotateEnableRequest;
3218//Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3219
3220 if (Amotor != IntPtr.Zero)
3221 {
3222 d.JointDestroy(Amotor);
3223 Amotor = IntPtr.Zero;
3224//Console.WriteLine("Old Amotor Destroyed");
3225 }
3226
3227 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3228 { // not all are enabled
3229 d.Quaternion r = d.BodyGetQuaternion(Body);
3230 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3231 // extract the axes vectors
3232 Vector3 vX = new Vector3(1f,0f,0f);
3233 Vector3 vY = new Vector3(0f,1f,0f);
3234 Vector3 vZ = new Vector3(0f,0f,1f);
3235 vX = vX * locrot;
3236 vY = vY * locrot;
3237 vZ = vZ * locrot;
3238 // snapshot the current angle vectors
3239 m_lockX = vX;
3240 m_lockY = vY;
3241 m_lockZ = vZ;
3242 // m_lockRot = locrot;
3243 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3244 d.JointAttach(Amotor, Body, IntPtr.Zero);
3245 d.JointSetAMotorMode(Amotor, 0); // User mode??
3246//Console.WriteLine("New Amotor Created for {0}", m_primName);
3247
3248 float axisnum = 3; // how many to lock
3249 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3250 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3251//Console.WriteLine("AxisNum={0}",(int)axisnum);
3252
3253 int i = 0;
3254
3255 if (m_rotateEnable.X == 0)
3256 {
3257 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3258//Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3259 i++;
3260 }
3261
3262 if (m_rotateEnable.Y == 0)
3263 {
3264 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3265//Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3266 i++;
3267 }
3268
3269 if (m_rotateEnable.Z == 0)
3270 {
3271 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3272//Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3273 i++;
3274 }
3275
3276 // These lowstops and high stops are effectively (no wiggle room)
3277 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3278 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3279 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3280 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3281 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3282 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3283 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3284 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3285 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3286 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3287 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3288 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3289 } // else none are locked
3290 } // end Rotation Update
3291
3292
3293 // VEHICLE processing ==========================================
3294 if (m_type != Vehicle.TYPE_NONE)
3295 {
3296 // get body attitude
3297 d.Quaternion rot = d.BodyGetQuaternion(Body);
3298 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3299 Quaternion irotq = Quaternion.Inverse(rotq);
3300
3301 // VEHICLE Linear Motion
3302 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3303 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3304 m_lLinObjectVel = vel_now * irotq;
3305 if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate
3306 {
3307 if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f)
3308 {
3309 float decayfactor = m_linearMotorDecayTimescale/timestep;
3310 Vector3 decayAmount = (m_lLinMotorDVel/decayfactor);
3311 m_lLinMotorDVel -= decayAmount;
3312 }
3313 else
3314 {
3315 float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale)));
3316 Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * timestep;
3317 m_lLinMotorDVel -= decel;
3318 }
3319 if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3320 {
3321 m_lLinMotorDVel = Vector3.Zero;
3322 }
3323
3324 /* else
3325 {
3326 if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X;
3327 if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y;
3328 if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z;
3329 } */
3330 } // end linear motor decay
3331
3332 if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3333 {
3334 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3335 if (m_linearMotorTimescale < 300.0f)
3336 {
3337 Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel;
3338 float linfactor = m_linearMotorTimescale/timestep;
3339 Vector3 attackAmount = (attack_error/linfactor) * 1.3f;
3340 m_lLinObjectVel += attackAmount;
3341 }
3342 if (m_linearFrictionTimescale.X < 300.0f)
3343 {
3344 float fricfactor = m_linearFrictionTimescale.X / timestep;
3345 float fricX = m_lLinObjectVel.X / fricfactor;
3346 m_lLinObjectVel.X -= fricX;
3347 }
3348 if (m_linearFrictionTimescale.Y < 300.0f)
3349 {
3350 float fricfactor = m_linearFrictionTimescale.Y / timestep;
3351 float fricY = m_lLinObjectVel.Y / fricfactor;
3352 m_lLinObjectVel.Y -= fricY;
3353 }
3354 if (m_linearFrictionTimescale.Z < 300.0f)
3355 {
3356 float fricfactor = m_linearFrictionTimescale.Z / timestep;
3357 float fricZ = m_lLinObjectVel.Z / fricfactor;
3358 m_lLinObjectVel.Z -= fricZ;
3359 }
3360 }
3361 m_wLinObjectVel = m_lLinObjectVel * rotq;
3362
3363 // Gravity and Buoyancy
3364 Vector3 grav = Vector3.Zero;
3365 if(m_VehicleBuoyancy < 1.0f)
3366 {
3367 // There is some gravity, make a gravity force vector
3368 // that is applied after object velocity.
3369 d.Mass objMass;
3370 d.BodyGetMass(Body, out objMass);
3371 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
3372 grav.Z = _parent_scene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force
3373 } // else its 1.0, no gravity.
3374
3375 // Hovering
3376 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
3377 {
3378 // We should hover, get the target height
3379 d.Vector3 pos = d.BodyGetPosition(Body);
3380 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
3381 {
3382 m_VhoverTargetHeight = _parent_scene.GetWaterLevel() + m_VhoverHeight;
3383 }
3384 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
3385 {
3386 m_VhoverTargetHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
3387 }
3388 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
3389 {
3390 m_VhoverTargetHeight = m_VhoverHeight;
3391 }
3392
3393 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
3394 {
3395 // If body is aready heigher, use its height as target height
3396 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
3397 }
3398
3399// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
3400// m_VhoverTimescale = 0f; // time to acheive height
3401// timestep is time since last frame,in secs
3402 float herr0 = pos.Z - m_VhoverTargetHeight;
3403 // Replace Vertical speed with correction figure if significant
3404 if(Math.Abs(herr0) > 0.01f )
3405 {
3406 //? d.Mass objMass;
3407 //? d.BodyGetMass(Body, out objMass);
3408 m_wLinObjectVel.Z = - ( (herr0 * timestep * 50.0f) / m_VhoverTimescale);
3409 //KF: m_VhoverEfficiency is not yet implemented
3410 }
3411 else
3412 {
3413 m_wLinObjectVel.Z = 0f;
3414 }
3415 }
3416 else
3417 { // not hovering
3418 if (m_wLinObjectVel.Z == 0f)
3419 { // Gravity rules
3420 m_wLinObjectVel.Z = vel_now.Z;
3421 } // else the motor has it
3422 }
3423 linvel = m_wLinObjectVel;
3424
3425 // Vehicle Linear Motion done =======================================
3426 // Apply velocity
3427 d.BodySetLinearVel(Body, linvel.X, linvel.Y, linvel.Z);
3428 // apply gravity force
3429 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
3430//if(frcount == 0) Console.WriteLine("Vel={0} Force={1}",linvel , grav);
3431 // end MoveLinear()
3432
3433
3434 // MoveAngular
3435 /*
3436 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
3437
3438 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
3439 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
3440 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
3441
3442 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
3443 private Vector3 m_angObjectVel = Vector3.Zero; // what was last applied to body
3444 */
3445//if(frcount == 0) Console.WriteLine("MoveAngular ");
3446
3447 d.Vector3 angularObjectVel = d.BodyGetAngularVel(Body);
3448 Vector3 angObjectVel = new Vector3(angularObjectVel.X, angularObjectVel.Y, angularObjectVel.Z);
3449 angObjectVel = angObjectVel * irotq; // ============ Converts to LOCAL rotation
3450
3451//if(frcount == 0) Console.WriteLine("V0 = {0}", angObjectVel);
3452
3453 // Decay Angular Motor 1. In SL this also depends on attack rate! decay ~= 23/Attack.
3454 float atk_decayfactor = 23.0f / (m_angularMotorTimescale * timestep);
3455 m_angularMotorDVel -= m_angularMotorDVel / atk_decayfactor;
3456 // Decay Angular Motor 2.
3457 if (m_angularMotorDecayTimescale < 300.0f)
3458 {
3459 if ( Vector3.Mag(m_angularMotorDVel) < 1.0f)
3460 {
3461 float decayfactor = (m_angularMotorDecayTimescale)/timestep;
3462 Vector3 decayAmount = (m_angularMotorDVel/decayfactor);
3463 m_angularMotorDVel -= decayAmount;
3464 }
3465 else
3466 {
3467 Vector3 decel = Vector3.Normalize(m_angularMotorDVel) * timestep / m_angularMotorDecayTimescale;
3468 m_angularMotorDVel -= decel;
3469 }
3470
3471 if (m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3472 {
3473 m_angularMotorDVel = Vector3.Zero;
3474 }
3475 else
3476 {
3477 if (Math.Abs(m_angularMotorDVel.X) < Math.Abs(angObjectVel.X)) angObjectVel.X = m_angularMotorDVel.X;
3478 if (Math.Abs(m_angularMotorDVel.Y) < Math.Abs(angObjectVel.Y)) angObjectVel.Y = m_angularMotorDVel.Y;
3479 if (Math.Abs(m_angularMotorDVel.Z) < Math.Abs(angObjectVel.Z)) angObjectVel.Z = m_angularMotorDVel.Z;
3480 }
3481 } // end decay angular motor
3482//if(frcount == 0) Console.WriteLine("MotorDvel {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3483
3484//if(frcount == 0) Console.WriteLine("VA = {0}", angObjectVel);
3485
3486 if ( (! m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! angObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3487 { // if motor or object have motion
3488 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3489
3490 if (m_angularMotorTimescale < 300.0f)
3491 {
3492 Vector3 attack_error = m_angularMotorDVel - angObjectVel;
3493 float angfactor = m_angularMotorTimescale/timestep;
3494 Vector3 attackAmount = (attack_error/angfactor);
3495 angObjectVel += attackAmount;
3496//if(frcount == 0) Console.WriteLine("Accel {0} Attk {1}",FrAaccel, attackAmount);
3497//if(frcount == 0) Console.WriteLine("V2+= {0}", angObjectVel);
3498 }
3499
3500 angObjectVel.X -= angObjectVel.X / (m_angularFrictionTimescale.X * 0.7f / timestep);
3501 angObjectVel.Y -= angObjectVel.Y / (m_angularFrictionTimescale.Y * 0.7f / timestep);
3502 angObjectVel.Z -= angObjectVel.Z / (m_angularFrictionTimescale.Z * 0.7f / timestep);
3503 } // else no signif. motion
3504
3505//if(frcount == 0) Console.WriteLine("Dmotor {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3506 // Bank section tba
3507 // Deflection section tba
3508//if(frcount == 0) Console.WriteLine("V3 = {0}", angObjectVel);
3509
3510
3511 /* // Rotation Axis Disables:
3512 if (!m_angularEnable.ApproxEquals(Vector3.One, 0.003f))
3513 {
3514 if (m_angularEnable.X == 0)
3515 angObjectVel.X = 0f;
3516 if (m_angularEnable.Y == 0)
3517 angObjectVel.Y = 0f;
3518 if (m_angularEnable.Z == 0)
3519 angObjectVel.Z = 0f;
3520 }
3521 */
3522 angObjectVel = angObjectVel * rotq; // ================ Converts to WORLD rotation
3523
3524 // Vertical attractor section
3525 Vector3 vertattr = Vector3.Zero;
3526
3527 if(m_verticalAttractionTimescale < 300)
3528 {
3529 float VAservo = 1.0f / (m_verticalAttractionTimescale * timestep);
3530 // make a vector pointing up
3531 Vector3 verterr = Vector3.Zero;
3532 verterr.Z = 1.0f;
3533 // rotate it to Body Angle
3534 verterr = verterr * rotq;
3535 // 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.
3536 // 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
3537 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
3538
3539 if (verterr.Z < 0.0f)
3540 { // Deflection from vertical exceeds 90-degrees. This method will ensure stable return to
3541 // vertical, BUT for some reason a z-rotation is imparted to the object. TBI.
3542//Console.WriteLine("InvertFlip");
3543 verterr.X = 2.0f - verterr.X;
3544 verterr.Y = 2.0f - verterr.Y;
3545 }
3546 verterr *= 0.5f;
3547 // verterror is 0 (no error) to +/- 1 (max error at 180-deg tilt)
3548 Vector3 xyav = angObjectVel;
3549 xyav.Z = 0.0f;
3550 if ((!xyav.ApproxEquals(Vector3.Zero, 0.001f)) || (verterr.Z < 0.49f))
3551 {
3552 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
3553 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
3554 vertattr.X = verterr.Y;
3555 vertattr.Y = - verterr.X;
3556 vertattr.Z = 0f;
3557//if(frcount == 0) Console.WriteLine("VAerr=" + verterr);
3558
3559 // scaling appears better usingsquare-law
3560 float damped = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
3561 float bounce = 1.0f - damped;
3562 // 0 = crit damp, 1 = bouncy
3563 float oavz = angObjectVel.Z; // retain z velocity
3564 // time-scaled correction, which sums, therefore is bouncy:
3565 angObjectVel = (angObjectVel + (vertattr * VAservo * 0.0333f)) * bounce;
3566 // damped, good @ < 90:
3567 angObjectVel = angObjectVel + (vertattr * VAservo * 0.0667f * damped);
3568 angObjectVel.Z = oavz;
3569//if(frcount == 0) Console.WriteLine("VA+");
3570//Console.WriteLine("VAttr {0} OAvel {1}", vertattr, angObjectVel);
3571 }
3572 else
3573 {
3574 // else error is very small
3575 angObjectVel.X = 0f;
3576 angObjectVel.Y = 0f;
3577//if(frcount == 0) Console.WriteLine("VA0");
3578 }
3579 } // else vertical attractor is off
3580//if(frcount == 0) Console.WriteLine("V1 = {0}", angObjectVel);
3581
3582
3583 m_lastAngularVelocity = angObjectVel;
3584 // apply Angular Velocity to body
3585 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
3586//if(frcount == 0) Console.WriteLine("V4 = {0}", m_lastAngularVelocity);
3587
3588 } // end VEHICLES
3589 else
3590 {
3591 // Dyamics (NON-'VEHICLES') are dealt with here ================================================================
3592
3593 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
3594
3595 /// Dynamics Buoyancy
3596 //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle.
3597 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
3598 // NB Prims in ODE are no subject to global gravity
3599 // This should only affect gravity operations
3600
3601 float m_mass = CalculateMass();
3602 // calculate z-force due togravity on object.
3603 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass
3604 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3605 {
3606 fz = 0; // llMoveToTarget ignores gravity.
3607 // it also ignores mass of object, and any physical resting on it.
3608 // Vector3 m_PIDTarget is where we are going
3609 // float m_PIDTau is time to get there
3610 fx = 0;
3611 fy = 0;
3612 d.Vector3 pos = d.BodyGetPosition(Body);
3613 Vector3 error = new Vector3(
3614 (m_PIDTarget.X - pos.X),
3615 (m_PIDTarget.Y - pos.Y),
3616 (m_PIDTarget.Z - pos.Z));
3617 if (error.ApproxEquals(Vector3.Zero,0.01f))
3618 { // Very close, Jump there and quit move
3619
3620 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3621 _target_velocity = Vector3.Zero;
3622 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3623 }
3624 else
3625 {
3626 float scale = 50.0f * timestep / m_PIDTau;
3627 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3628 {
3629 // Nearby, quit update of velocity
3630 }
3631 else
3632 { // Far, calc damped velocity
3633 _target_velocity = error * scale;
3634 }
3635 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3636 }
3637 } // end PID MoveToTarget
3638
3639
3640 /// Dynamics Hover ===================================================================================
3641 // Hover PID Controller can only run if the PIDcontroller is not in use.
3642 if (m_useHoverPID && !m_usePID)
3643 {
3644//Console.WriteLine("Hover " + m_primName);
3645
3646 // If we're using the PID controller, then we have no gravity
3647 fz = (-1 * _parent_scene.gravityz) * m_mass;
3648
3649 // no lock; for now it's only called from within Simulate()
3650
3651 // If the PID Controller isn't active then we set our force
3652 // calculating base velocity to the current position
3653
3654 if ((m_PIDTau < 1))
3655 {
3656 PID_G = PID_G / m_PIDTau;
3657 }
3658
3659 if ((PID_G - m_PIDTau) <= 0)
3660 {
3661 PID_G = m_PIDTau + 1;
3662 }
3663
3664
3665 // Where are we, and where are we headed?
3666 d.Vector3 pos = d.BodyGetPosition(Body);
3667// d.Vector3 vel = d.BodyGetLinearVel(Body);
3668
3669
3670 // Non-Vehicles have a limited set of Hover options.
3671 // determine what our target height really is based on HoverType
3672 switch (m_PIDHoverType)
3673 {
3674 case PIDHoverType.Ground:
3675 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3676 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3677 break;
3678 case PIDHoverType.GroundAndWater:
3679 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3680 m_waterHeight = _parent_scene.GetWaterLevel();
3681 if (m_groundHeight > m_waterHeight)
3682 {
3683 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3684 }
3685 else
3686 {
3687 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3688 }
3689 break;
3690
3691 } // end switch (m_PIDHoverType)
3692
3693
3694 _target_velocity =
3695 new Vector3(0.0f, 0.0f,
3696 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3697 );
3698
3699 // if velocity is zero, use position control; otherwise, velocity control
3700
3701 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3702 {
3703 // keep track of where we stopped. No more slippin' & slidin'
3704
3705 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3706 // react to the physics scene by moving it's position.
3707 // Avatar to Avatar collisions
3708 // Prim to avatar collisions
3709 d.Vector3 dlinvel = vel;
3710 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3711 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3712 d.BodyAddForce(Body, 0, 0, fz);
3713 //KF this prevents furthur motions return;
3714 }
3715 else
3716 {
3717 _zeroFlag = false;
3718
3719 // We're flying and colliding with something
3720 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3721 }
3722 } // end m_useHoverPID && !m_usePID
3723
3724
3725 /// Dynamics Apply Forces ===================================================================================
3726 fx *= m_mass;
3727 fy *= m_mass;
3728 //fz *= m_mass;
3729 fx += m_force.X;
3730 fy += m_force.Y;
3731 fz += m_force.Z;
3732
3733 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3734 if (fx != 0 || fy != 0 || fz != 0)
3735 {
3736 //m_taintdisable = true;
3737 //base.RaiseOutOfBounds(Position);
3738 //d.BodySetLinearVel(Body, fx, fy, 0f);
3739 if (!d.BodyIsEnabled(Body))
3740 {
3741 // A physical body at rest on a surface will auto-disable after a while,
3742 // this appears to re-enable it incase the surface it is upon vanishes,
3743 // and the body should fall again.
3744 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3745 d.BodySetForce(Body, 0f, 0f, 0f);
3746 enableBodySoft();
3747 }
3748
3749 // 35x10 = 350n times the mass per second applied maximum.
3750 float nmax = 35f * m_mass;
3751 float nmin = -35f * m_mass;
3752
3753
3754 if (fx > nmax)
3755 fx = nmax;
3756 if (fx < nmin)
3757 fx = nmin;
3758 if (fy > nmax)
3759 fy = nmax;
3760 if (fy < nmin)
3761 fy = nmin;
3762 d.BodyAddForce(Body, fx, fy, fz);
3763 } // end apply forces
3764 } // end Vehicle/Dynamics
3765
3766 /// RotLookAt / LookAt =================================================================================
3767 if (m_useAPID)
3768 {
3769 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3770 // Quaternion m_APIDTarget
3771 // float m_APIDStrength // From SL experiments, this is the time to get there
3772 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3773 // Also in SL the mass of the object has no effect on time to get there.
3774 // Factors:
3775 // get present body rotation
3776 float limit = 1.0f;
3777 float rscaler = 50f; // adjusts rotation damping time
3778 float lscaler = 10f; // adjusts linear damping time in llLookAt
3779 float RLAservo = 0f;
3780 Vector3 diff_axis;
3781 float diff_angle;
3782 d.Quaternion rot = d.BodyGetQuaternion(Body); // prim present rotation
3783 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3784 Quaternion rtarget = new Quaternion();
3785
3786 if(m_APIDTarget.W == -99.9f)
3787 {
3788 // this is really a llLookAt(), x,y,z is the target vector
3789 Vector3 target = new Vector3(m_APIDTarget.X, m_APIDTarget.Y, m_APIDTarget.Z);
3790 Vector3 ospin = new Vector3(1.0f, 0.0f, 0.0f) * rotq;
3791 Vector3 error = new Vector3(0.0f, 0.0f, 0.0f);
3792 float twopi = 2.0f * (float)Math.PI;
3793 Vector3 dir = target - _position;
3794 dir.Normalize();
3795 float tzrot = (float)Math.Atan2(dir.Y, dir.X);
3796 float txy = (float)Math.Sqrt((dir.X * dir.X) + (dir.Y * dir.Y));
3797 float terot = (float)Math.Atan2(dir.Z, txy);
3798 float ozrot = (float)Math.Atan2(ospin.Y, ospin.X);
3799 float oxy = (float)Math.Sqrt((ospin.X * ospin.X) + (ospin.Y * ospin.Y));
3800 float oerot = (float)Math.Atan2(ospin.Z, oxy);
3801 float ra = 2.0f * ((rotq.W * rotq.X) + (rotq.Y * rotq.Z));
3802 float rb = 1.0f - 2.0f * ((rotq.Y * rotq.Y)+(rotq.X * rotq.X));
3803 float roll = (float)Math.Atan2(ra, rb);
3804 float errorz = tzrot - ozrot;
3805 if(errorz > (float)Math.PI) errorz -= twopi;
3806 else if(errorz < -(float)Math.PI) errorz += twopi;
3807 float errory = oerot - terot;
3808 if(errory > (float)Math.PI) errory -= twopi;
3809 else if(errory < -(float)Math.PI) errory += twopi;
3810 diff_angle = Math.Abs(errorz) + Math.Abs(errory) + Math.Abs(roll);
3811 if(diff_angle > 0.01f * m_APIDdamper)
3812 {
3813 m_APIDdamper = 1.0f;
3814 RLAservo = timestep / m_APIDStrength * rscaler;
3815 errorz *= RLAservo;
3816 errory *= RLAservo;
3817 error.X = -roll * 8.0f;
3818 error.Y = errory;
3819 error.Z = errorz;
3820 error *= rotq;
3821 d.BodySetAngularVel (Body, error.X, error.Y, error.Z);
3822 }
3823 else
3824 {
3825 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3826 m_APIDdamper = 2.0f;
3827 }
3828 }
3829 else
3830 {
3831 // this is a llRotLookAt()
3832 rtarget = m_APIDTarget;
3833
3834 Quaternion rot_diff = Quaternion.Inverse(rotq) * rtarget; // difference to desired rot
3835 rot_diff.GetAxisAngle(out diff_axis, out diff_angle); // convert to axis to point at & error angle
3836//if(frcount == 0) Console.WriteLine("axis {0} angle {1}",diff_axis * 57.3f, diff_angle);
3837
3838 // diff_axis.Normalize(); it already is!
3839 if(diff_angle > 0.01f * m_APIDdamper) // diff_angle is always +ve // if there is enough error
3840 {
3841 m_APIDdamper = 1.0f;
3842 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3843 rotforce = rotforce * rotq;
3844 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3845 RLAservo = timestep / m_APIDStrength * lscaler;
3846 rotforce = rotforce * RLAservo * diff_angle ;
3847 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3848//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3849 }
3850 else
3851 { // close enough
3852 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3853 m_APIDdamper = 2.0f;
3854 }
3855 } // end llLookAt/llRotLookAt
3856//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3857 } // end m_useAPID
3858 } // end root prims
3859 } // end Move()
3860 } // end class
3861}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..7314107
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,375 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending Raycast Requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Scene that created this object.
54 /// </summary>
55 private OdeScene m_scene;
56
57 /// <summary>
58 /// ODE contact array to be filled by the collision testing
59 /// </summary>
60 d.ContactGeom[] contacts = new d.ContactGeom[5];
61
62 /// <summary>
63 /// ODE near callback delegate
64 /// </summary>
65 private d.NearCallback nearCallback;
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private List<ContactResult> m_contactResults = new List<ContactResult>();
68
69
70 public ODERayCastRequestManager(OdeScene pScene)
71 {
72 m_scene = pScene;
73 nearCallback = near;
74
75 }
76
77 /// <summary>
78 /// Queues a raycast
79 /// </summary>
80 /// <param name="position">Origin of Ray</param>
81 /// <param name="direction">Ray normal</param>
82 /// <param name="length">Ray length</param>
83 /// <param name="retMethod">Return method to send the results</param>
84 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
85 {
86 lock (m_PendingRequests)
87 {
88 ODERayCastRequest req = new ODERayCastRequest();
89 req.callbackMethod = retMethod;
90 req.length = length;
91 req.Normal = direction;
92 req.Origin = position;
93
94 m_PendingRequests.Add(req);
95 }
96 }
97
98 /// <summary>
99 /// Process all queued raycast requests
100 /// </summary>
101 /// <returns>Time in MS the raycasts took to process.</returns>
102 public int ProcessQueuedRequests()
103 {
104 int time = System.Environment.TickCount;
105 lock (m_PendingRequests)
106 {
107 if (m_PendingRequests.Count > 0)
108 {
109 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
110 for (int i = 0; i < reqs.Length; i++)
111 {
112 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
113 RayCast(reqs[i]); // if there isn't anyone to send results
114 }
115 /*
116 foreach (ODERayCastRequest req in m_PendingRequests)
117 {
118 if (req.callbackMethod != null) // quick optimization here, don't raycast
119 RayCast(req); // if there isn't anyone to send results to
120
121 }
122 */
123 m_PendingRequests.Clear();
124 }
125 }
126
127 lock (m_contactResults)
128 m_contactResults.Clear();
129
130 return System.Environment.TickCount - time;
131 }
132
133 /// <summary>
134 /// Method that actually initiates the raycast
135 /// </summary>
136 /// <param name="req"></param>
137 private void RayCast(ODERayCastRequest req)
138 {
139 // Create the ray
140 IntPtr ray = d.CreateRay(m_scene.space, req.length);
141 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
142
143 // Collide test
144 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
145
146 // Remove Ray
147 d.GeomDestroy(ray);
148
149
150 // Define default results
151 bool hitYN = false;
152 uint hitConsumerID = 0;
153 float distance = 999999999999f;
154 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
155 Vector3 snormal = Vector3.Zero;
156
157 // Find closest contact and object.
158 lock (m_contactResults)
159 {
160 foreach (ContactResult cResult in m_contactResults)
161 {
162 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
163 {
164 closestcontact = cResult.Pos;
165 hitConsumerID = cResult.ConsumerID;
166 distance = cResult.Depth;
167 hitYN = true;
168 snormal = cResult.Normal;
169 }
170 }
171
172 m_contactResults.Clear();
173 }
174
175 // Return results
176 if (req.callbackMethod != null)
177 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
178 }
179
180 // This is the standard Near. Uses space AABBs to speed up detection.
181 private void near(IntPtr space, IntPtr g1, IntPtr g2)
182 {
183
184 //Don't test against heightfield Geom, or you'll be sorry!
185
186 /*
187 terminate called after throwing an instance of 'std::bad_alloc'
188 what(): std::bad_alloc
189 Stacktrace:
190
191 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
192 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
193 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
194 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
195 fffff>
196 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
197 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
198 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
199 0x00114>
200 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
201 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
202 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
203 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
204 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
205 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
206
207 Native stacktrace:
208
209 mono [0x80d2a42]
210 [0xb7f5840c]
211 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
212 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
213 /usr/lib/libstdc++.so.6 [0xb45fa865]
214 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
215 /usr/lib/libstdc++.so.6 [0xb45fa9da]
216 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
217 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
218 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
219 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
220 libode.so(dCollide+0x102) [0xb46571b2]
221 [0x95cfdec9]
222 [0x8ea07fe1]
223 [0xab260146]
224 libode.so [0xb465a5c4]
225 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
226 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
227 [0x95cf978e]
228 [0x8ea07945]
229 [0x95cf2bbc]
230 [0xab2787e7]
231 [0xab419fb3]
232 [0xab416657]
233 [0xab415bda]
234 [0xb609b08e]
235 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
236 mono [0x81a2f0f]
237 mono [0x81d28b6]
238 mono [0x81ea2c6]
239 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
240 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
241 */
242
243 // Exclude heightfield geom
244
245 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
246 return;
247 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
248 return;
249
250 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
251 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
252 {
253 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
254 return;
255
256 // Separating static prim geometry spaces.
257 // We'll be calling near recursivly if one
258 // of them is a space to find all of the
259 // contact points in the space
260 try
261 {
262 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
263 }
264 catch (AccessViolationException)
265 {
266 m_log.Warn("[PHYSICS]: Unable to collide test a space");
267 return;
268 }
269 //Colliding a space or a geom with a space or a geom. so drill down
270
271 //Collide all geoms in each space..
272 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
273 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
274 return;
275 }
276
277 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
278 return;
279
280 int count = 0;
281 try
282 {
283
284 if (g1 == g2)
285 return; // Can't collide with yourself
286
287 lock (contacts)
288 {
289 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
290 }
291 }
292 catch (SEHException)
293 {
294 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
295 }
296 catch (Exception e)
297 {
298 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
299 return;
300 }
301
302 PhysicsActor p1 = null;
303 PhysicsActor p2 = null;
304
305 if (g1 != IntPtr.Zero)
306 m_scene.actor_name_map.TryGetValue(g1, out p1);
307
308 if (g2 != IntPtr.Zero)
309 m_scene.actor_name_map.TryGetValue(g1, out p2);
310
311 // Loop over contacts, build results.
312 for (int i = 0; i < count; i++)
313 {
314 if (p1 != null) {
315 if (p1 is OdePrim)
316 {
317 ContactResult collisionresult = new ContactResult();
318
319 collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
320 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
321 collisionresult.Depth = contacts[i].depth;
322 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
323 contacts[i].normal.Z);
324 lock (m_contactResults)
325 m_contactResults.Add(collisionresult);
326 }
327 }
328
329 if (p2 != null)
330 {
331 if (p2 is OdePrim)
332 {
333 ContactResult collisionresult = new ContactResult();
334
335 collisionresult.ConsumerID = ((OdePrim)p2).m_localID;
336 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
337 collisionresult.Depth = contacts[i].depth;
338 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
339 contacts[i].normal.Z);
340
341 lock (m_contactResults)
342 m_contactResults.Add(collisionresult);
343 }
344 }
345
346
347 }
348
349 }
350
351 /// <summary>
352 /// Dereference the creator scene so that it can be garbage collected if needed.
353 /// </summary>
354 internal void Dispose()
355 {
356 m_scene = null;
357 }
358 }
359
360 public struct ODERayCastRequest
361 {
362 public Vector3 Origin;
363 public Vector3 Normal;
364 public float length;
365 public RaycastCallback callbackMethod;
366 }
367
368 public struct ContactResult
369 {
370 public Vector3 Pos;
371 public float Depth;
372 public uint ConsumerID;
373 public Vector3 Normal;
374 }
375}
diff --git a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
index ca7a4f8..b4a3c48 100644
--- a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
@@ -26,51 +26,23 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using OpenMetaverse;
30using Nini.Config; 30using Ode.NET;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
33using PhysXWrapper; 33using OpenSim.Region.Physics.OdePlugin;
34using Quaternion=OpenMetaverse.Quaternion;
35using System.Reflection;
36using log4net;
37using OpenMetaverse;
38 34
39namespace OpenSim.Region.Physics.PhysXPlugin 35namespace OpenSim.Region.Physics.OdePlugin
40{ 36{
41 /// <summary> 37 class OdePhysicsJoint : PhysicsJoint
42 /// Will be the PhysX plugin but for now will be a very basic physics engine
43 /// </summary>
44 public class PhysXPlugin : IPhysicsPlugin
45 { 38 {
46 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 public override bool IsInPhysicsEngine
47 private PhysXScene _mScene;
48
49 public PhysXPlugin()
50 {
51 }
52
53 public bool Init()
54 { 40 {
55 return true; 41 get
56 }
57
58 public PhysicsScene GetScene(string sceneIdentifier)
59 {
60 if (_mScene == null)
61 { 42 {
62 _mScene = new PhysXScene(sceneIdentifier); 43 return (jointID != IntPtr.Zero);
63 } 44 }
64 return (_mScene);
65 }
66
67 public string GetName()
68 {
69 return ("RealPhysX");
70 }
71
72 public void Dispose()
73 {
74 } 45 }
46 public IntPtr jointID;
75 } 47 }
76} 48}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
new file mode 100644
index 0000000..88f9658
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3846 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//#define USE_DRAWSTUFF
29
30using System;
31using System.Collections.Generic;
32using System.Reflection;
33using System.Runtime.InteropServices;
34using System.Threading;
35using System.IO;
36using System.Diagnostics;
37using log4net;
38using Nini.Config;
39using Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager;
45using OpenMetaverse;
46
47//using OpenSim.Region.Physics.OdePlugin.Meshing;
48
49namespace OpenSim.Region.Physics.OdePlugin
50{
51 /// <summary>
52 /// ODE plugin
53 /// </summary>
54 public class OdePlugin : IPhysicsPlugin
55 {
56 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
57
58 private CollisionLocker ode;
59 private OdeScene _mScene;
60
61 public OdePlugin()
62 {
63 ode = new CollisionLocker();
64 }
65
66 public bool Init()
67 {
68 return true;
69 }
70
71 public PhysicsScene GetScene(String sceneIdentifier)
72 {
73 if (_mScene == null)
74 {
75 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
76 // http://opensimulator.org/mantis/view.php?id=2750).
77 d.InitODE();
78
79 _mScene = new OdeScene(ode, sceneIdentifier);
80 }
81 return (_mScene);
82 }
83
84 public string GetName()
85 {
86 return ("ChODE");
87 }
88
89 public void Dispose()
90 {
91 }
92 }
93
94 public enum StatusIndicators : int
95 {
96 Generic = 0,
97 Start = 1,
98 End = 2
99 }
100
101 public struct sCollisionData
102 {
103 public uint ColliderLocalId;
104 public uint CollidedWithLocalId;
105 public int NumberOfCollisions;
106 public int CollisionType;
107 public int StatusIndicator;
108 public int lastframe;
109 }
110
111 [Flags]
112 public enum CollisionCategories : int
113 {
114 Disabled = 0,
115 Geom = 0x00000001,
116 Body = 0x00000002,
117 Space = 0x00000004,
118 Character = 0x00000008,
119 Land = 0x00000010,
120 Water = 0x00000020,
121 Wind = 0x00000040,
122 Sensor = 0x00000080,
123 Selected = 0x00000100
124 }
125
126 /// <summary>
127 /// Material type for a primitive
128 /// </summary>
129 public enum Material : int
130 {
131 /// <summary></summary>
132 Stone = 0,
133 /// <summary></summary>
134 Metal = 1,
135 /// <summary></summary>
136 Glass = 2,
137 /// <summary></summary>
138 Wood = 3,
139 /// <summary></summary>
140 Flesh = 4,
141 /// <summary></summary>
142 Plastic = 5,
143 /// <summary></summary>
144 Rubber = 6
145
146 }
147
148 public sealed class OdeScene : PhysicsScene
149 {
150 private readonly ILog m_log;
151 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
152
153 CollisionLocker ode;
154
155 private Random fluidRandomizer = new Random(Environment.TickCount);
156
157 private const uint m_regionWidth = Constants.RegionSize;
158 private const uint m_regionHeight = Constants.RegionSize;
159
160 private float ODE_STEPSIZE = 0.020f;
161 private float metersInSpace = 29.9f;
162 private float m_timeDilation = 1.0f;
163
164 public float gravityx = 0f;
165 public float gravityy = 0f;
166 public float gravityz = -9.8f;
167
168 private float contactsurfacelayer = 0.001f;
169
170 private int worldHashspaceLow = -4;
171 private int worldHashspaceHigh = 128;
172
173 private int smallHashspaceLow = -4;
174 private int smallHashspaceHigh = 66;
175
176 private float waterlevel = 0f;
177 private int framecount = 0;
178 //private int m_returncollisions = 10;
179
180 private readonly IntPtr contactgroup;
181
182 internal IntPtr LandGeom;
183 internal IntPtr WaterGeom;
184
185 private float nmTerrainContactFriction = 255.0f;
186 private float nmTerrainContactBounce = 0.1f;
187 private float nmTerrainContactERP = 0.1025f;
188
189 private float mTerrainContactFriction = 75f;
190 private float mTerrainContactBounce = 0.1f;
191 private float mTerrainContactERP = 0.05025f;
192
193 private float nmAvatarObjectContactFriction = 250f;
194 private float nmAvatarObjectContactBounce = 0.1f;
195
196 private float mAvatarObjectContactFriction = 75f;
197 private float mAvatarObjectContactBounce = 0.1f;
198
199 private float avPIDD = 3200f;
200 private float avPIDP = 1400f;
201 private float avCapRadius = 0.37f;
202 private float avStandupTensor = 2000000f;
203 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
204 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
205 private float avDensity = 80f;
206 private float avHeightFudgeFactor = 0.52f;
207 private float avMovementDivisorWalk = 1.3f;
208 private float avMovementDivisorRun = 0.8f;
209 private float minimumGroundFlightOffset = 3f;
210 public float maximumMassObject = 10000.01f;
211
212 public bool meshSculptedPrim = true;
213 public bool forceSimplePrimMeshing = false;
214
215 public float meshSculptLOD = 32;
216 public float MeshSculptphysicalLOD = 16;
217
218 public float geomDefaultDensity = 10.000006836f;
219
220 public int geomContactPointsStartthrottle = 3;
221 public int geomUpdatesPerThrottledUpdate = 15;
222
223 public float bodyPIDD = 35f;
224 public float bodyPIDG = 25;
225
226 public int geomCrossingFailuresBeforeOutofbounds = 5;
227 public float geomRegionFence = 0.0f;
228
229 public float bodyMotorJointMaxforceTensor = 2;
230
231 public int bodyFramesAutoDisable = 20;
232
233 private DateTime m_lastframe = DateTime.UtcNow;
234
235 private float[] _watermap;
236 private bool m_filterCollisions = true;
237
238 private d.NearCallback nearCallback;
239 public d.TriCallback triCallback;
240 public d.TriArrayCallback triArrayCallback;
241 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
242 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
243 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
244 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
245 private readonly Object _taintedPrimLock = new Object();
246 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
247 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
248 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
249 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
250 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
251 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
252 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
253 private bool m_NINJA_physics_joints_enabled = false;
254 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
255 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
256 private d.ContactGeom[] contacts;
257 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
258 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
259 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
260 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
261 private Object externalJointRequestsLock = new Object();
262 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
263 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
264 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
265 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
266
267 private d.Contact ContactCopy; // local copy that can be modified
268 private d.Contact TerrainContact;
269 private d.Contact AvatarStaticprimContact; // was 'contact'
270 private d.Contact AvatarMovementprimContact;
271 private d.Contact AvatarMovementTerrainContact;
272 private d.Contact WaterContact;
273 private d.Contact[,] m_materialContacts;
274
275//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
276//Ckrinke private int m_randomizeWater = 200;
277 private int m_physicsiterations = 10;
278 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
279 private readonly PhysicsActor PANull = new NullPhysicsActor();
280 private float step_time = 0.0f;
281//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
282//Ckrinke private int ms = 0;
283 public IntPtr world;
284 //private bool returncollisions = false;
285 // private uint obj1LocalID = 0;
286 private uint obj2LocalID = 0;
287 //private int ctype = 0;
288 private OdeCharacter cc1;
289 private OdePrim cp1;
290 private OdeCharacter cc2;
291 private OdePrim cp2;
292 //private int cStartStop = 0;
293 //private string cDictKey = "";
294
295 public IntPtr space;
296
297 //private IntPtr tmpSpace;
298 // split static geometry collision handling into spaces of 30 meters
299 public IntPtr[,] staticPrimspace;
300
301 public Object OdeLock;
302
303 public IMesher mesher;
304
305 private IConfigSource m_config;
306
307 public bool physics_logging = false;
308 public int physics_logging_interval = 0;
309 public bool physics_logging_append_existing_logfile = false;
310
311 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
312 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
313
314 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
315 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
316 // TODO: unused: private uint heightmapWidthSamples;
317 // TODO: unused: private uint heightmapHeightSamples;
318
319 private volatile int m_global_contactcount = 0;
320
321 private Vector3 m_worldOffset = Vector3.Zero;
322 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
323 private PhysicsScene m_parentScene = null;
324
325 private ODERayCastRequestManager m_rayCastManager;
326
327 /// <summary>
328 /// Initiailizes the scene
329 /// Sets many properties that ODE requires to be stable
330 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
331 /// </summary>
332 public OdeScene(CollisionLocker dode, string sceneIdentifier)
333 {
334 m_log
335 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
336
337 OdeLock = new Object();
338 ode = dode;
339 nearCallback = near;
340 triCallback = TriCallback;
341 triArrayCallback = TriArrayCallback;
342 m_rayCastManager = new ODERayCastRequestManager(this);
343 lock (OdeLock)
344 {
345 // Create the world and the first space
346 world = d.WorldCreate();
347 space = d.HashSpaceCreate(IntPtr.Zero);
348
349
350 contactgroup = d.JointGroupCreate(0);
351 //contactgroup
352
353 d.WorldSetAutoDisableFlag(world, false);
354 #if USE_DRAWSTUFF
355
356 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
357 viewthread.Start();
358 #endif
359 }
360
361
362 _watermap = new float[258 * 258];
363
364 // Zero out the prim spaces array (we split our space into smaller spaces so
365 // we can hit test less.
366 }
367
368#if USE_DRAWSTUFF
369 public void startvisualization(object o)
370 {
371 ds.Functions fn;
372 fn.version = ds.VERSION;
373 fn.start = new ds.CallbackFunction(start);
374 fn.step = new ds.CallbackFunction(step);
375 fn.command = new ds.CallbackFunction(command);
376 fn.stop = null;
377 fn.path_to_textures = "./textures";
378 string[] args = new string[0];
379 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
380 }
381#endif
382
383 // Initialize the mesh plugin
384 public override void Initialise(IMesher meshmerizer, IConfigSource config)
385 {
386 mesher = meshmerizer;
387 m_config = config;
388 // Defaults
389
390 if (Environment.OSVersion.Platform == PlatformID.Unix)
391 {
392 avPIDD = 3200.0f;
393 avPIDP = 1400.0f;
394 avStandupTensor = 2000000f;
395 }
396 else
397 {
398 avPIDD = 2200.0f;
399 avPIDP = 900.0f;
400 avStandupTensor = 550000f;
401 }
402
403 int contactsPerCollision = 80;
404
405 if (m_config != null)
406 {
407 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
408 if (physicsconfig != null)
409 {
410 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
411 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
412 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
413
414 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
415 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
416
417 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
418 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
419 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
420
421 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
422
423 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
424 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
425 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
426
427 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
428 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
429 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
430
431 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
432 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
433
434 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
435 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
436
437 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
438 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
439
440 avDensity = physicsconfig.GetFloat("av_density", 80f);
441 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
442 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
443 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
444 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
445 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
446
447 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
448
449 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
450 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
451 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
452 geomRegionFence = physicsconfig.GetFloat("region_border_fence", 0.0f);
453
454 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
455 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
456
457 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
458 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
459
460 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
461 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
462 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
463 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
464 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
465
466 if (Environment.OSVersion.Platform == PlatformID.Unix)
467 {
468 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
469 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
470 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
471 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
472 }
473 else
474 {
475 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
476 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
477 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
478 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
479 }
480
481 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
482 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
483 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
484
485 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
488 }
489 }
490
491 contacts = new d.ContactGeom[contactsPerCollision];
492
493 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
494
495 // Avatar static on a Prim parameters
496 AvatarStaticprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
497 AvatarStaticprimContact.surface.mu = 255.0f;
498 AvatarStaticprimContact.surface.bounce = 0.0f;
499 AvatarStaticprimContact.surface.soft_cfm = 0.0f;
500 AvatarStaticprimContact.surface.soft_erp = 0.30f; // If this is too small static Av will fall through a sloping prim. 1.0 prevents fall-thru
501
502 // Avatar moving on a Prim parameters
503 AvatarMovementprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
504 AvatarMovementprimContact.surface.mu = 255.0f;
505 AvatarMovementprimContact.surface.bounce = 0.0f;
506 AvatarMovementprimContact.surface.soft_cfm = 0.0f; // if this is 0.01 then prims become phantom to Avs!
507 AvatarMovementprimContact.surface.soft_erp = 0.3f;
508
509 // Static Avatar on Terrain parameters
510 // Keeps Avatar in place better
511 TerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
512 TerrainContact.surface.mu = 255.0f;
513 TerrainContact.surface.bounce = 0.0f;
514 TerrainContact.surface.soft_cfm = 0.0f;
515 TerrainContact.surface.soft_erp = 0.05f;
516
517 // Moving Avatar on Terrain parameters
518 AvatarMovementTerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
519 AvatarMovementTerrainContact.surface.mu = 75f;
520 AvatarMovementTerrainContact.surface.bounce = 0.0f;
521 AvatarMovementTerrainContact.surface.soft_cfm = 0.0f;
522 AvatarMovementTerrainContact.surface.soft_erp = 0.05f;
523
524 // Avatar or prim the the water, this may not be used, possibly water is same as air?
525 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
526 WaterContact.surface.mu = 0.0f; // No friction
527 WaterContact.surface.bounce = 0.0f; // No bounce
528 WaterContact.surface.soft_cfm = 0.010f;
529 WaterContact.surface.soft_erp = 0.010f;
530
531
532 // Prim static or moving on a prim, depends on material type
533 m_materialContacts = new d.Contact[7,2];
534 // V 1 = Sliding; 0 = static or fell onto
535 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
536 m_materialContacts[(int)Material.Stone, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
537 m_materialContacts[(int)Material.Stone, 0].surface.mu = 60f; // friction, 1 = slippery, 255 = no slip
538 m_materialContacts[(int)Material.Stone, 0].surface.bounce = 0.0f;
539 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.0f;
540 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.50f; // erp also changes friction, more erp=less friction
541
542 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
543 m_materialContacts[(int)Material.Stone, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
544 m_materialContacts[(int)Material.Stone, 1].surface.mu = 40f;
545 m_materialContacts[(int)Material.Stone, 1].surface.bounce = 0.0f;
546 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.0f;
547 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.50f;
548
549 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
550 m_materialContacts[(int)Material.Metal, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
551 m_materialContacts[(int)Material.Metal, 0].surface.mu = 15f;
552 m_materialContacts[(int)Material.Metal, 0].surface.bounce = 0.2f;
553 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.0f;
554 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.50f;
555
556 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
557 m_materialContacts[(int)Material.Metal, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
558 m_materialContacts[(int)Material.Metal, 1].surface.mu = 10f;
559 m_materialContacts[(int)Material.Metal, 1].surface.bounce = 0.2f;
560 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.0f;
561 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.50f;
562
563 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
564 m_materialContacts[(int)Material.Glass, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
565 m_materialContacts[(int)Material.Glass, 0].surface.mu = 7.5f;
566 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.0f;
567 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.0f;
568 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.50f;
569
570 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
571 m_materialContacts[(int)Material.Glass, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
572 m_materialContacts[(int)Material.Glass, 1].surface.mu = 5f;
573 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.0f;
574 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.0f;
575 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.50f;
576
577 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
578 m_materialContacts[(int)Material.Wood, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
579 m_materialContacts[(int)Material.Wood, 0].surface.mu = 45f;
580 m_materialContacts[(int)Material.Wood, 0].surface.bounce = 0.1f;
581 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.0f;
582 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.50f;
583
584 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
585 m_materialContacts[(int)Material.Wood, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
586 m_materialContacts[(int)Material.Wood, 1].surface.mu = 30f;
587 m_materialContacts[(int)Material.Wood, 1].surface.bounce = 0.1f;
588 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.0f;
589 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.50f;
590
591 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
592 m_materialContacts[(int)Material.Flesh, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
593 m_materialContacts[(int)Material.Flesh, 0].surface.mu = 150f;
594 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = 0.0f;
595 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.0f;
596 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.50f;
597
598 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
599 m_materialContacts[(int)Material.Flesh, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
600 m_materialContacts[(int)Material.Flesh, 1].surface.mu = 100f;
601 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = 0.0f;
602 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.0f;
603 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.50f;
604
605 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
606 m_materialContacts[(int)Material.Plastic, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
607 m_materialContacts[(int)Material.Plastic, 0].surface.mu = 30f;
608 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = 0.2f;
609 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.0f;
610 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.50f;
611
612 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
613 m_materialContacts[(int)Material.Plastic, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
614 m_materialContacts[(int)Material.Plastic, 1].surface.mu = 20f;
615 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = 0.2f;
616 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.0f;
617 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.50f;
618
619 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
620 m_materialContacts[(int)Material.Rubber, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
621 m_materialContacts[(int)Material.Rubber, 0].surface.mu = 150f;
622 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = 0.7f;
623 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.0f;
624 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.50f;
625
626 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
627 m_materialContacts[(int)Material.Rubber, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
628 m_materialContacts[(int)Material.Rubber, 1].surface.mu = 100f;
629 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = 0.7f;
630 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.0f;
631 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.50f;
632
633 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
634
635 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
636
637 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
638 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
639
640
641 d.WorldSetLinearDampingThreshold(world, 256f);
642 d.WorldSetLinearDamping(world, 256f);
643// d.WorldSetLinearDampingThreshold(world, 0.01f);
644// d.WorldSetLinearDamping(world, 0.1f);
645 d.WorldSetAngularDampingThreshold(world, 256f);
646 d.WorldSetAngularDamping(world, 256f);
647 d.WorldSetMaxAngularSpeed(world, 256f);
648
649 // Set how many steps we go without running collision testing
650 // This is in addition to the step size.
651 // Essentially Steps * m_physicsiterations
652 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
653 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
654
655
656
657 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
658 {
659 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
660 {
661 staticPrimspace[i, j] = IntPtr.Zero;
662 }
663 }
664 }
665
666 internal void waitForSpaceUnlock(IntPtr space)
667 {
668 //if (space != IntPtr.Zero)
669 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
670 }
671
672 /// <summary>
673 /// Debug space message for printing the space that a prim/avatar is in.
674 /// </summary>
675 /// <param name="pos"></param>
676 /// <returns>Returns which split up space the given position is in.</returns>
677 public string whichspaceamIin(Vector3 pos)
678 {
679 return calculateSpaceForGeom(pos).ToString();
680 }
681
682 #region Collision Detection
683
684 /// <summary>
685 /// This is our near callback. A geometry is near a body
686 /// </summary>
687 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
688 /// <param name="g1">a geometry or space</param>
689 /// <param name="g2">another geometry or space</param>
690 private void near(IntPtr space, IntPtr g1, IntPtr g2)
691 {
692 // no lock here! It's invoked from within Simulate(), which is thread-locked
693
694 // Test if we're colliding a geom with a space.
695 // If so we have to drill down into the space recursively
696//Console.WriteLine("near -----------"); //##
697 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
698 {
699 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
700 return;
701
702 // Separating static prim geometry spaces.
703 // We'll be calling near recursivly if one
704 // of them is a space to find all of the
705 // contact points in the space
706 try
707 {
708 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
709 }
710 catch (AccessViolationException)
711 {
712 m_log.Warn("[PHYSICS]: Unable to collide test a space");
713 return;
714 }
715 //Colliding a space or a geom with a space or a geom. so drill down
716
717 //Collide all geoms in each space..
718 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
719 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
720 return;
721 }
722
723 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
724 return;
725
726 IntPtr b1 = d.GeomGetBody(g1);
727 IntPtr b2 = d.GeomGetBody(g2);
728
729 // d.GeomClassID id = d.GeomGetClass(g1);
730
731 String name1 = null;
732 String name2 = null;
733
734 if (!geom_name_map.TryGetValue(g1, out name1))
735 {
736 name1 = "null";
737 }
738 if (!geom_name_map.TryGetValue(g2, out name2))
739 {
740 name2 = "null";
741 }
742
743 //if (id == d.GeomClassId.TriMeshClass)
744 //{
745 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
746 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
747 //}
748
749 // Figure out how many contact points we have
750 int count = 0;
751 try
752 {
753 // Colliding Geom To Geom
754 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
755
756 if (g1 == g2)
757 return; // Can't collide with yourself
758
759 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
760 return;
761
762 lock (contacts)
763 {
764 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
765 if (count > contacts.Length)
766 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
767 }
768 }
769 catch (SEHException)
770 {
771 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
772 ode.drelease(world);
773 base.TriggerPhysicsBasedRestart();
774 }
775 catch (Exception e)
776 {
777 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
778 return;
779 }
780
781 PhysicsActor p1;
782 PhysicsActor p2;
783
784 if (!actor_name_map.TryGetValue(g1, out p1))
785 {
786 p1 = PANull;
787 }
788
789 if (!actor_name_map.TryGetValue(g2, out p2))
790 {
791 p2 = PANull;
792 }
793
794 ContactPoint maxDepthContact = new ContactPoint();
795 if (p1.CollisionScore + count >= float.MaxValue)
796 p1.CollisionScore = 0;
797 p1.CollisionScore += count;
798
799 if (p2.CollisionScore + count >= float.MaxValue)
800 p2.CollisionScore = 0;
801 p2.CollisionScore += count;
802 for (int i = 0; i < count; i++)
803 {
804 d.ContactGeom curContact = contacts[i];
805
806 if (curContact.depth > maxDepthContact.PenetrationDepth)
807 {
808 maxDepthContact = new ContactPoint(
809 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
810 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
811 curContact.depth
812 );
813 }
814
815 //m_log.Warn("[CCOUNT]: " + count);
816 IntPtr joint;
817 // If we're colliding with terrain, use 'TerrainContact' instead of AvatarStaticprimContact.
818 // allows us to have different settings
819
820 // We only need to test p2 for 'jump crouch purposes'
821 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
822 {
823 // Testing if the collision is at the feet of the avatar
824
825 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
826//#@ if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
827//#@ p2.IsColliding = true;
828 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)){ //##
829 p2.IsColliding = true; //##
830 }else{
831
832 } //##
833 }
834 else
835 {
836 p2.IsColliding = true;
837 }
838
839 //if ((framecount % m_returncollisions) == 0)
840
841 switch (p1.PhysicsActorType)
842 {
843 case (int)ActorTypes.Agent:
844 p2.CollidingObj = true;
845 break;
846 case (int)ActorTypes.Prim:
847 if (p2.Velocity.LengthSquared() > 0.0f)
848 p2.CollidingObj = true;
849 break;
850 case (int)ActorTypes.Unknown:
851 p2.CollidingGround = true;
852 break;
853 default:
854 p2.CollidingGround = true;
855 break;
856 }
857
858 // we don't want prim or avatar to explode
859
860 #region InterPenetration Handling - Unintended physics explosions
861# region disabled code1
862
863 if (curContact.depth >= 0.08f)
864 {
865 //This is disabled at the moment only because it needs more tweaking
866 //It will eventually be uncommented
867 /*
868 if (AvatarStaticprimContact.depth >= 1.00f)
869 {
870 //m_log.Debug("[PHYSICS]: " + AvatarStaticprimContact.depth.ToString());
871 }
872
873 //If you interpenetrate a prim with an agent
874 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
875 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
876 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
877 p2.PhysicsActorType == (int) ActorTypes.Prim))
878 {
879
880 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth * 4.15f;
881 /*
882 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
883 {
884 p2.CollidingObj = true;
885 AvatarStaticprimContact.depth = 0.003f;
886 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
887 OdeCharacter character = (OdeCharacter) p2;
888 character.SetPidStatus(true);
889 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p1.Size.X / 2), AvatarStaticprimContact.pos.Y + (p1.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p1.Size.Z / 2));
890
891 }
892 else
893 {
894
895 //AvatarStaticprimContact.depth = 0.0000000f;
896 }
897 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
898 {
899
900 p1.CollidingObj = true;
901 AvatarStaticprimContact.depth = 0.003f;
902 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
903 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p2.Size.X / 2), AvatarStaticprimContact.pos.Y + (p2.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p2.Size.Z / 2));
904 OdeCharacter character = (OdeCharacter)p1;
905 character.SetPidStatus(true);
906 }
907 else
908 {
909
910 //AvatarStaticprimContact.depth = 0.0000000f;
911 }
912
913
914
915 }
916*/
917 // If you interpenetrate a prim with another prim
918 /*
919 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
920 {
921 #region disabledcode2
922 //OdePrim op1 = (OdePrim)p1;
923 //OdePrim op2 = (OdePrim)p2;
924 //op1.m_collisionscore++;
925 //op2.m_collisionscore++;
926
927 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
928 //{
929 //op1.m_taintdisable = true;
930 //AddPhysicsActorTaint(p1);
931 //op2.m_taintdisable = true;
932 //AddPhysicsActorTaint(p2);
933 //}
934
935 //if (AvatarStaticprimContact.depth >= 0.25f)
936 //{
937 // Don't collide, one or both prim will expld.
938
939 //op1.m_interpenetrationcount++;
940 //op2.m_interpenetrationcount++;
941 //interpenetrations_before_disable = 200;
942 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
943 //{
944 //op1.m_taintdisable = true;
945 //AddPhysicsActorTaint(p1);
946 //}
947 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
948 //{
949 // op2.m_taintdisable = true;
950 //AddPhysicsActorTaint(p2);
951 //}
952
953 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth / 8f;
954 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
955 //}
956 //if (op1.m_disabled || op2.m_disabled)
957 //{
958 //Manually disabled objects stay disabled
959 //AvatarStaticprimContact.depth = 0f;
960 //}
961 #endregion
962 }
963 */
964#endregion
965 if (curContact.depth >= 1.00f)
966 {
967 //m_log.Info("[P]: " + AvatarStaticprimContact.depth.ToString());
968 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
969 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
970 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
971 p2.PhysicsActorType == (int) ActorTypes.Unknown))
972 {
973 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
974 {
975 if (p2 is OdeCharacter)
976 {
977 OdeCharacter character = (OdeCharacter) p2;
978
979 //p2.CollidingObj = true;
980 curContact.depth = 0.00000003f;
981 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
982 curContact.pos =
983 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
984 curContact.pos.Y + (p1.Size.Y/2),
985 curContact.pos.Z + (p1.Size.Z/2));
986 character.SetPidStatus(true);
987 }
988 }
989
990
991 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
992 {
993 if (p1 is OdeCharacter)
994 {
995 OdeCharacter character = (OdeCharacter) p1;
996
997 //p2.CollidingObj = true;
998 curContact.depth = 0.00000003f;
999 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1000 curContact.pos =
1001 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1002 curContact.pos.Y + (p1.Size.Y/2),
1003 curContact.pos.Z + (p1.Size.Z/2));
1004 character.SetPidStatus(true);
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 #endregion
1012
1013 // Logic for collision handling
1014 // Note, that if *all* contacts are skipped (VolumeDetect)
1015 // The prim still detects (and forwards) collision events but
1016 // appears to be phantom for the world
1017 Boolean skipThisContact = false;
1018
1019 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1020 skipThisContact = true; // No collision on volume detect prims
1021
1022 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1023 skipThisContact = true; // No collision on volume detect prims
1024
1025 if (!skipThisContact && curContact.depth < 0f)
1026 skipThisContact = true;
1027
1028 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1029 skipThisContact = true;
1030
1031 const int maxContactsbeforedeath = 4000;
1032 joint = IntPtr.Zero;
1033
1034 if (!skipThisContact)
1035 {
1036 // Add contact joints with materials params----------------------------------
1037 // p1 is what is being hit, p2 is the physical object doing the hitting
1038 int material = (int) Material.Wood;
1039 int movintYN = 0; // 1 = Sliding; 0 = static or fell onto
1040 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) movintYN = 1;
1041
1042 // If we're colliding against terrain
1043 if (name1 == "Terrain" || name2 == "Terrain")
1044 {
1045 // If we're moving
1046 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && (movintYN == 1))
1047 {
1048 //$ Av walk/run on terrain (not falling) Use the Avatar movement terrain contact
1049 AvatarMovementTerrainContact.geom = curContact;
1050 _perloopContact.Add(curContact);
1051 if (m_global_contactcount < maxContactsbeforedeath)
1052 {
1053 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1054 m_global_contactcount++;
1055 }
1056 }
1057 else
1058 {
1059 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1060 {
1061 //$ Av standing on terrain, Use the non moving Avata terrain contact
1062 TerrainContact.geom = curContact;
1063 _perloopContact.Add(curContact);
1064 if (m_global_contactcount < maxContactsbeforedeath)
1065 {
1066 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1067 m_global_contactcount++;
1068 }
1069 }
1070 else
1071 {
1072 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1073 {
1074 //& THIS NEVER HAPPENS? prim prim contact In terrain contact?
1075 // int pj294950 = 0;
1076 // prim terrain contact
1077
1078 if (p2 is OdePrim)
1079 material = ((OdePrim)p2).m_material;
1080 //m_log.DebugFormat("Material: {0}", material);
1081 m_materialContacts[material, movintYN].geom = curContact;
1082 _perloopContact.Add(curContact);
1083
1084 if (m_global_contactcount < maxContactsbeforedeath)
1085 {
1086 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1087 m_global_contactcount++;
1088
1089 }
1090
1091 }
1092 else
1093 {
1094 //$ prim on terrain contact
1095 if (p2 is OdePrim)
1096 material = ((OdePrim)p2).m_material;
1097 //m_log.DebugFormat("Material: {0}", material);
1098 m_materialContacts[material, movintYN].geom = curContact;
1099 _perloopContact.Add(curContact);
1100
1101 ContactCopy = m_materialContacts[material, movintYN];
1102 if(movintYN == 1)
1103 {
1104 // prevent excessive slide on terrain
1105 ContactCopy.surface.mu = m_materialContacts[material, movintYN].surface.mu * 30.0f;
1106 }
1107
1108 if (m_global_contactcount < maxContactsbeforedeath)
1109 {
1110 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1111 m_global_contactcount++;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 else if (name1 == "Water" || name2 == "Water")
1118 {
1119 //$ This never happens! Perhaps water is treated like air?
1120 /*
1121 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1122 {
1123 }
1124 else
1125 {
1126 }
1127 */
1128 //WaterContact.surface.soft_cfm = 0.0000f;
1129 //WaterContact.surface.soft_erp = 0.00000f;
1130 if (curContact.depth > 0.1f)
1131 {
1132 curContact.depth *= 52;
1133 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
1134 //AvatarStaticprimContact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1135 }
1136 WaterContact.geom = curContact;
1137 _perloopContact.Add(curContact);
1138 if (m_global_contactcount < maxContactsbeforedeath)
1139 {
1140 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1141 m_global_contactcount++;
1142 }
1143 //m_log.Info("[PHYSICS]: Prim Water Contact" + AvatarStaticprimContact.depth);
1144 }
1145 else
1146 {
1147
1148 // no terrain and no water, we're colliding with prim or avatar
1149 // check if we're moving
1150 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1151 {
1152 //$ Avatar on Prim or other Avatar
1153 if (movintYN == 1)
1154 {
1155 // Use the AV Movement / prim contact
1156 AvatarMovementprimContact.geom = curContact;
1157 _perloopContact.Add(curContact);
1158 if (m_global_contactcount < maxContactsbeforedeath)
1159 {
1160 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1161 m_global_contactcount++;
1162 }
1163 }
1164 else
1165 {
1166 // Use the Av non movement / prim contact
1167 AvatarStaticprimContact.geom = curContact;
1168 _perloopContact.Add(curContact);
1169 ContactCopy = AvatarStaticprimContact; // local copy so we can change locally
1170
1171 if (m_global_contactcount < maxContactsbeforedeath)
1172 {
1173 if (curContact.depth > 0.2)
1174 { // embedded, eject slowly
1175 ContactCopy.surface.soft_erp = 0.1f;
1176 ContactCopy.surface.soft_cfm = 0.1f;
1177 }
1178 else
1179 { // keep on the surface
1180 ContactCopy.surface.soft_erp = 0.3f;
1181 ContactCopy.surface.soft_cfm = 0.0f;
1182 }
1183 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1184 m_global_contactcount++;
1185 }
1186 }
1187 }
1188 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1189 {
1190 //$ Prim on Prim
1191 //p1.PhysicsActorType
1192
1193 if (p2 is OdePrim) material = ((OdePrim)p2).m_material;
1194 //m_log.DebugFormat("Material: {0}", material);
1195
1196 m_materialContacts[material, movintYN].geom = curContact;
1197 _perloopContact.Add(curContact);
1198
1199 if (m_global_contactcount < maxContactsbeforedeath)
1200 {
1201 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1202 m_global_contactcount++;
1203 }
1204 }
1205 }
1206
1207 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1208 {
1209 d.JointAttach(joint, b1, b2);
1210 m_global_contactcount++;
1211 }
1212
1213 }
1214 collision_accounting_events(p1, p2, maxDepthContact);
1215 if (count > geomContactPointsStartthrottle)
1216 {
1217 // If there are more then 3 contact points, it's likely
1218 // that we've got a pile of objects, so ...
1219 // We don't want to send out hundreds of terse updates over and over again
1220 // so lets throttle them and send them again after it's somewhat sorted out.
1221 p2.ThrottleUpdates = true;
1222 }
1223 //m_log.Debug(count.ToString());
1224 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1225 } // end for i.. loop
1226 } // end near
1227
1228 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1229 {
1230 bool result = false;
1231 //return result;
1232 if (!m_filterCollisions)
1233 return false;
1234
1235 ActorTypes at = (ActorTypes)atype;
1236 lock (_perloopContact)
1237 {
1238 foreach (d.ContactGeom contact in _perloopContact)
1239 {
1240 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1241 //{
1242 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1243 if (at == ActorTypes.Agent)
1244 {
1245 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1246 {
1247
1248 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1249 {
1250 //contactGeom.depth *= .00005f;
1251 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1252 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1253 result = true;
1254 break;
1255 }
1256 else
1257 {
1258 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1259 }
1260 }
1261 else
1262 {
1263 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1264 //int i = 0;
1265 }
1266 }
1267 else if (at == ActorTypes.Prim)
1268 {
1269 //d.AABB aabb1 = new d.AABB();
1270 //d.AABB aabb2 = new d.AABB();
1271
1272 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1273 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1274 //aabb1.
1275 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1276 {
1277 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1278 {
1279 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1280 {
1281 result = true;
1282 break;
1283 }
1284 }
1285 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1286 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1287 }
1288
1289 }
1290
1291 //}
1292
1293 }
1294 }
1295 return result;
1296 }
1297
1298 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1299 {
1300 // obj1LocalID = 0;
1301 //returncollisions = false;
1302 obj2LocalID = 0;
1303 //ctype = 0;
1304 //cStartStop = 0;
1305 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1306 return;
1307
1308 switch ((ActorTypes)p2.PhysicsActorType)
1309 {
1310 case ActorTypes.Agent:
1311 cc2 = (OdeCharacter)p2;
1312
1313 // obj1LocalID = cc2.m_localID;
1314 switch ((ActorTypes)p1.PhysicsActorType)
1315 {
1316 case ActorTypes.Agent:
1317 cc1 = (OdeCharacter)p1;
1318 obj2LocalID = cc1.m_localID;
1319 cc1.AddCollisionEvent(cc2.m_localID, contact);
1320 //ctype = (int)CollisionCategories.Character;
1321
1322 //if (cc1.CollidingObj)
1323 //cStartStop = (int)StatusIndicators.Generic;
1324 //else
1325 //cStartStop = (int)StatusIndicators.Start;
1326
1327 //returncollisions = true;
1328 break;
1329 case ActorTypes.Prim:
1330 if (p1 is OdePrim)
1331 {
1332 cp1 = (OdePrim) p1;
1333 obj2LocalID = cp1.m_localID;
1334 cp1.AddCollisionEvent(cc2.m_localID, contact);
1335 }
1336 //ctype = (int)CollisionCategories.Geom;
1337
1338 //if (cp1.CollidingObj)
1339 //cStartStop = (int)StatusIndicators.Generic;
1340 //else
1341 //cStartStop = (int)StatusIndicators.Start;
1342
1343 //returncollisions = true;
1344 break;
1345
1346 case ActorTypes.Ground:
1347 case ActorTypes.Unknown:
1348 obj2LocalID = 0;
1349 //ctype = (int)CollisionCategories.Land;
1350 //returncollisions = true;
1351 break;
1352 }
1353
1354 cc2.AddCollisionEvent(obj2LocalID, contact);
1355 break;
1356 case ActorTypes.Prim:
1357
1358 if (p2 is OdePrim)
1359 {
1360 cp2 = (OdePrim) p2;
1361
1362 // obj1LocalID = cp2.m_localID;
1363 switch ((ActorTypes) p1.PhysicsActorType)
1364 {
1365 case ActorTypes.Agent:
1366 if (p1 is OdeCharacter)
1367 {
1368 cc1 = (OdeCharacter) p1;
1369 obj2LocalID = cc1.m_localID;
1370 cc1.AddCollisionEvent(cp2.m_localID, contact);
1371 //ctype = (int)CollisionCategories.Character;
1372
1373 //if (cc1.CollidingObj)
1374 //cStartStop = (int)StatusIndicators.Generic;
1375 //else
1376 //cStartStop = (int)StatusIndicators.Start;
1377 //returncollisions = true;
1378 }
1379 break;
1380 case ActorTypes.Prim:
1381
1382 if (p1 is OdePrim)
1383 {
1384 cp1 = (OdePrim) p1;
1385 obj2LocalID = cp1.m_localID;
1386 cp1.AddCollisionEvent(cp2.m_localID, contact);
1387 //ctype = (int)CollisionCategories.Geom;
1388
1389 //if (cp1.CollidingObj)
1390 //cStartStop = (int)StatusIndicators.Generic;
1391 //else
1392 //cStartStop = (int)StatusIndicators.Start;
1393
1394 //returncollisions = true;
1395 }
1396 break;
1397
1398 case ActorTypes.Ground:
1399 case ActorTypes.Unknown:
1400 obj2LocalID = 0;
1401 //ctype = (int)CollisionCategories.Land;
1402
1403 //returncollisions = true;
1404 break;
1405 }
1406
1407 cp2.AddCollisionEvent(obj2LocalID, contact);
1408 }
1409 break;
1410 }
1411 //if (returncollisions)
1412 //{
1413
1414 //lock (m_storedCollisions)
1415 //{
1416 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1417 //if (m_storedCollisions.ContainsKey(cDictKey))
1418 //{
1419 //sCollisionData objd = m_storedCollisions[cDictKey];
1420 //objd.NumberOfCollisions += 1;
1421 //objd.lastframe = framecount;
1422 //m_storedCollisions[cDictKey] = objd;
1423 //}
1424 //else
1425 //{
1426 //sCollisionData objd = new sCollisionData();
1427 //objd.ColliderLocalId = obj1LocalID;
1428 //objd.CollidedWithLocalId = obj2LocalID;
1429 //objd.CollisionType = ctype;
1430 //objd.NumberOfCollisions = 1;
1431 //objd.lastframe = framecount;
1432 //objd.StatusIndicator = cStartStop;
1433 //m_storedCollisions.Add(cDictKey, objd);
1434 //}
1435 //}
1436 // }
1437 }
1438
1439 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1440 {
1441 /* String name1 = null;
1442 String name2 = null;
1443
1444 if (!geom_name_map.TryGetValue(trimesh, out name1))
1445 {
1446 name1 = "null";
1447 }
1448 if (!geom_name_map.TryGetValue(refObject, out name2))
1449 {
1450 name2 = "null";
1451 }
1452
1453 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1454 */
1455 return 1;
1456 }
1457
1458 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1459 {
1460 String name1 = null;
1461 String name2 = null;
1462
1463 if (!geom_name_map.TryGetValue(trimesh, out name1))
1464 {
1465 name1 = "null";
1466 }
1467
1468 if (!geom_name_map.TryGetValue(refObject, out name2))
1469 {
1470 name2 = "null";
1471 }
1472
1473 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1474
1475 d.Vector3 v0 = new d.Vector3();
1476 d.Vector3 v1 = new d.Vector3();
1477 d.Vector3 v2 = new d.Vector3();
1478
1479 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1480 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1481
1482 return 1;
1483 }
1484
1485 /// <summary>
1486 /// This is our collision testing routine in ODE
1487 /// </summary>
1488 /// <param name="timeStep"></param>
1489 private void collision_optimized(float timeStep)
1490 {
1491 _perloopContact.Clear();
1492
1493 lock (_characters)
1494 {
1495 foreach (OdeCharacter chr in _characters)
1496 {
1497 // Reset the collision values to false
1498 // since we don't know if we're colliding yet
1499
1500 // For some reason this can happen. Don't ask...
1501 //
1502 if (chr == null)
1503 continue;
1504
1505 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1506 continue;
1507
1508 chr.IsColliding = false;
1509 chr.CollidingGround = false;
1510 chr.CollidingObj = false;
1511
1512 // test the avatar's geometry for collision with the space
1513 // This will return near and the space that they are the closest to
1514 // And we'll run this again against the avatar and the space segment
1515 // This will return with a bunch of possible objects in the space segment
1516 // and we'll run it again on all of them.
1517 try
1518 {
1519 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1520 }
1521 catch (AccessViolationException)
1522 {
1523 m_log.Warn("[PHYSICS]: Unable to space collide");
1524 }
1525 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1526 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1527 //{
1528 //chr.Position.Z = terrainheight + 10.0f;
1529 //forcedZ = true;
1530 //}
1531 }
1532 }
1533
1534 lock (_activeprims)
1535 {
1536 List<OdePrim> removeprims = null;
1537 foreach (OdePrim chr in _activeprims)
1538 {
1539 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1540 {
1541 try
1542 {
1543 lock (chr)
1544 {
1545 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1546 {
1547 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1548 }
1549 else
1550 {
1551 if (removeprims == null)
1552 {
1553 removeprims = new List<OdePrim>();
1554 }
1555 removeprims.Add(chr);
1556 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1557 }
1558 }
1559 }
1560 catch (AccessViolationException)
1561 {
1562 m_log.Warn("[PHYSICS]: Unable to space collide");
1563 }
1564 }
1565 }
1566 if (removeprims != null)
1567 {
1568 foreach (OdePrim chr in removeprims)
1569 {
1570 _activeprims.Remove(chr);
1571 }
1572 }
1573 }
1574
1575 _perloopContact.Clear();
1576 }
1577
1578 #endregion
1579
1580 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1581 {
1582 m_worldOffset = offset;
1583 WorldExtents = new Vector2(extents.X, extents.Y);
1584 m_parentScene = pScene;
1585
1586 }
1587
1588 // Recovered for use by fly height. Kitto Flora
1589 public float GetTerrainHeightAtXY(float x, float y)
1590 {
1591
1592 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1593 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1594
1595 IntPtr heightFieldGeom = IntPtr.Zero;
1596
1597 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1598 {
1599 if (heightFieldGeom != IntPtr.Zero)
1600 {
1601 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1602 {
1603
1604 int index;
1605
1606
1607 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1608 (int)x < 0.001f || (int)y < 0.001f)
1609 return 0;
1610
1611 x = x - offsetX;
1612 y = y - offsetY;
1613
1614 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1615
1616 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1617 {
1618 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1619 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1620 }
1621
1622 else
1623 return 0f;
1624 }
1625 else
1626 {
1627 return 0f;
1628 }
1629
1630 }
1631 else
1632 {
1633 return 0f;
1634 }
1635
1636 }
1637 else
1638 {
1639 return 0f;
1640 }
1641
1642
1643 }
1644// End recovered. Kitto Flora
1645
1646 public void addCollisionEventReporting(PhysicsActor obj)
1647 {
1648 lock (_collisionEventPrim)
1649 {
1650 if (!_collisionEventPrim.Contains(obj))
1651 _collisionEventPrim.Add(obj);
1652 }
1653 }
1654
1655 public void remCollisionEventReporting(PhysicsActor obj)
1656 {
1657 lock (_collisionEventPrim)
1658 {
1659 if (!_collisionEventPrim.Contains(obj))
1660 _collisionEventPrim.Remove(obj);
1661 }
1662 }
1663
1664 #region Add/Remove Entities
1665
1666 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1667 {
1668 Vector3 pos;
1669 pos.X = position.X;
1670 pos.Y = position.Y;
1671 pos.Z = position.Z;
1672 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1673 newAv.Flying = isFlying;
1674 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1675
1676 return newAv;
1677 }
1678
1679 public void AddCharacter(OdeCharacter chr)
1680 {
1681 lock (_characters)
1682 {
1683 if (!_characters.Contains(chr))
1684 {
1685 _characters.Add(chr);
1686 if (chr.bad)
1687 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1688 }
1689 }
1690 }
1691
1692 public void RemoveCharacter(OdeCharacter chr)
1693 {
1694 lock (_characters)
1695 {
1696 if (_characters.Contains(chr))
1697 {
1698 _characters.Remove(chr);
1699 }
1700 }
1701 }
1702 public void BadCharacter(OdeCharacter chr)
1703 {
1704 lock (_badCharacter)
1705 {
1706 if (!_badCharacter.Contains(chr))
1707 _badCharacter.Add(chr);
1708 }
1709 }
1710
1711 public override void RemoveAvatar(PhysicsActor actor)
1712 {
1713 //m_log.Debug("[PHYSICS]:ODELOCK");
1714 ((OdeCharacter) actor).Destroy();
1715
1716 }
1717
1718 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1719 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1720 {
1721
1722 Vector3 pos = position;
1723 Vector3 siz = size;
1724 Quaternion rot = rotation;
1725
1726 OdePrim newPrim;
1727 lock (OdeLock)
1728 {
1729 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1730
1731 lock (_prims)
1732 _prims.Add(newPrim);
1733 }
1734
1735 return newPrim;
1736 }
1737
1738 public void addActivePrim(OdePrim activatePrim)
1739 {
1740 // adds active prim.. (ones that should be iterated over in collisions_optimized
1741 lock (_activeprims)
1742 {
1743 if (!_activeprims.Contains(activatePrim))
1744 _activeprims.Add(activatePrim);
1745 //else
1746 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1747 }
1748 }
1749
1750 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1751 Vector3 size, Quaternion rotation) //To be removed
1752 {
1753 return AddPrimShape(primName, pbs, position, size, rotation, false);
1754 }
1755
1756 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1757 Vector3 size, Quaternion rotation, bool isPhysical)
1758 {
1759 PhysicsActor result;
1760 IMesh mesh = null;
1761
1762 if (needsMeshing(pbs))
1763 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1764
1765 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1766
1767 return result;
1768 }
1769
1770 public override float TimeDilation
1771 {
1772 get { return m_timeDilation; }
1773 }
1774
1775 public override bool SupportsNINJAJoints
1776 {
1777 get { return m_NINJA_physics_joints_enabled; }
1778 }
1779
1780 // internal utility function: must be called within a lock (OdeLock)
1781 private void InternalAddActiveJoint(PhysicsJoint joint)
1782 {
1783 activeJoints.Add(joint);
1784 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1785 }
1786
1787 // internal utility function: must be called within a lock (OdeLock)
1788 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1789 {
1790 pendingJoints.Add(joint);
1791 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1792 }
1793
1794 // internal utility function: must be called within a lock (OdeLock)
1795 private void InternalRemovePendingJoint(PhysicsJoint joint)
1796 {
1797 pendingJoints.Remove(joint);
1798 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1799 }
1800
1801 // internal utility function: must be called within a lock (OdeLock)
1802 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1803 {
1804 activeJoints.Remove(joint);
1805 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1806 }
1807
1808 public override void DumpJointInfo()
1809 {
1810 string hdr = "[NINJA] JOINTINFO: ";
1811 foreach (PhysicsJoint j in pendingJoints)
1812 {
1813 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1814 }
1815 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1816 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1817 {
1818 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1819 }
1820 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1821 foreach (PhysicsJoint j in activeJoints)
1822 {
1823 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1824 }
1825 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1826 foreach (string jointName in SOPName_to_activeJoint.Keys)
1827 {
1828 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1829 }
1830 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1831
1832 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1833 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1834 foreach (string actorName in joints_connecting_actor.Keys)
1835 {
1836 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1837 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1838 {
1839 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1840 }
1841 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1842 }
1843 }
1844
1845 public override void RequestJointDeletion(string ObjectNameInScene)
1846 {
1847 lock (externalJointRequestsLock)
1848 {
1849 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1850 {
1851 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1852 }
1853 }
1854 }
1855
1856 private void DeleteRequestedJoints()
1857 {
1858 List<string> myRequestedJointsToBeDeleted;
1859 lock (externalJointRequestsLock)
1860 {
1861 // make a local copy of the shared list for processing (threading issues)
1862 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1863 }
1864
1865 foreach (string jointName in myRequestedJointsToBeDeleted)
1866 {
1867 lock (OdeLock)
1868 {
1869 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1870 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1871 {
1872 OdePhysicsJoint joint = null;
1873 if (SOPName_to_activeJoint.ContainsKey(jointName))
1874 {
1875 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1876 InternalRemoveActiveJoint(joint);
1877 }
1878 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1879 {
1880 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1881 InternalRemovePendingJoint(joint);
1882 }
1883
1884 if (joint != null)
1885 {
1886 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1887 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1888 {
1889 string bodyName = joint.BodyNames[iBodyName];
1890 if (bodyName != "NULL")
1891 {
1892 joints_connecting_actor[bodyName].Remove(joint);
1893 if (joints_connecting_actor[bodyName].Count == 0)
1894 {
1895 joints_connecting_actor.Remove(bodyName);
1896 }
1897 }
1898 }
1899
1900 DoJointDeactivated(joint);
1901 if (joint.jointID != IntPtr.Zero)
1902 {
1903 d.JointDestroy(joint.jointID);
1904 joint.jointID = IntPtr.Zero;
1905 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1906 }
1907 else
1908 {
1909 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1910 }
1911 }
1912 else
1913 {
1914 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1915 }
1916 }
1917 else
1918 {
1919 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1920 }
1921 }
1922 }
1923
1924 // remove processed joints from the shared list
1925 lock (externalJointRequestsLock)
1926 {
1927 foreach (string jointName in myRequestedJointsToBeDeleted)
1928 {
1929 requestedJointsToBeDeleted.Remove(jointName);
1930 }
1931 }
1932 }
1933
1934 // for pending joints we don't know if their associated bodies exist yet or not.
1935 // the joint is actually created during processing of the taints
1936 private void CreateRequestedJoints()
1937 {
1938 List<PhysicsJoint> myRequestedJointsToBeCreated;
1939 lock (externalJointRequestsLock)
1940 {
1941 // make a local copy of the shared list for processing (threading issues)
1942 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1943 }
1944
1945 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1946 {
1947 lock (OdeLock)
1948 {
1949 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1950 {
1951 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1952 continue;
1953 }
1954 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1955 {
1956 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1957 continue;
1958 }
1959
1960 InternalAddPendingJoint(joint as OdePhysicsJoint);
1961
1962 if (joint.BodyNames.Count >= 2)
1963 {
1964 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1965 {
1966 string bodyName = joint.BodyNames[iBodyName];
1967 if (bodyName != "NULL")
1968 {
1969 if (!joints_connecting_actor.ContainsKey(bodyName))
1970 {
1971 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1972 }
1973 joints_connecting_actor[bodyName].Add(joint);
1974 }
1975 }
1976 }
1977 }
1978 }
1979
1980 // remove processed joints from shared list
1981 lock (externalJointRequestsLock)
1982 {
1983 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1984 {
1985 requestedJointsToBeCreated.Remove(joint);
1986 }
1987 }
1988
1989 }
1990
1991 // public function to add an request for joint creation
1992 // this joint will just be added to a waiting list that is NOT processed during the main
1993 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1994
1995 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1996 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1997
1998 {
1999
2000 OdePhysicsJoint joint = new OdePhysicsJoint();
2001 joint.ObjectNameInScene = objectNameInScene;
2002 joint.Type = jointType;
2003 joint.Position = position;
2004 joint.Rotation = rotation;
2005 joint.RawParams = parms;
2006 joint.BodyNames = new List<string>(bodyNames);
2007 joint.TrackedBodyName = trackedBodyName;
2008 joint.LocalRotation = localRotation;
2009 joint.jointID = IntPtr.Zero;
2010 joint.ErrorMessageCount = 0;
2011
2012 lock (externalJointRequestsLock)
2013 {
2014 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2015 {
2016 requestedJointsToBeCreated.Add(joint);
2017 }
2018 }
2019 return joint;
2020 }
2021
2022 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2023 {
2024 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2025 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2026 {
2027
2028 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2029 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2030 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2031 {
2032 jointsToRemove.Add(j);
2033 }
2034 foreach (PhysicsJoint j in jointsToRemove)
2035 {
2036 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2037 RequestJointDeletion(j.ObjectNameInScene);
2038 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2039 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2040 }
2041 }
2042 }
2043
2044 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2045 {
2046 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2047 lock (OdeLock)
2048 {
2049 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2050 RemoveAllJointsConnectedToActor(actor);
2051 }
2052 }
2053
2054 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2055 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2056 {
2057 Debug.Assert(joint.IsInPhysicsEngine);
2058 d.Vector3 pos = new d.Vector3();
2059
2060 if (!(joint is OdePhysicsJoint))
2061 {
2062 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2063 }
2064 else
2065 {
2066 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2067 switch (odeJoint.Type)
2068 {
2069 case PhysicsJointType.Ball:
2070 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2071 break;
2072 case PhysicsJointType.Hinge:
2073 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2074 break;
2075 }
2076 }
2077 return new Vector3(pos.X, pos.Y, pos.Z);
2078 }
2079
2080 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2081 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2082 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2083 // keeping track of the joint's original orientation relative to one of the involved bodies.
2084 public override Vector3 GetJointAxis(PhysicsJoint joint)
2085 {
2086 Debug.Assert(joint.IsInPhysicsEngine);
2087 d.Vector3 axis = new d.Vector3();
2088
2089 if (!(joint is OdePhysicsJoint))
2090 {
2091 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2092 }
2093 else
2094 {
2095 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2096 switch (odeJoint.Type)
2097 {
2098 case PhysicsJointType.Ball:
2099 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2100 break;
2101 case PhysicsJointType.Hinge:
2102 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2103 break;
2104 }
2105 }
2106 return new Vector3(axis.X, axis.Y, axis.Z);
2107 }
2108
2109
2110 public void remActivePrim(OdePrim deactivatePrim)
2111 {
2112 lock (_activeprims)
2113 {
2114 _activeprims.Remove(deactivatePrim);
2115 }
2116 }
2117
2118 public override void RemovePrim(PhysicsActor prim)
2119 {
2120 if (prim is OdePrim)
2121 {
2122 lock (OdeLock)
2123 {
2124 OdePrim p = (OdePrim) prim;
2125
2126 p.setPrimForRemoval();
2127 AddPhysicsActorTaint(prim);
2128 //RemovePrimThreadLocked(p);
2129 }
2130 }
2131 }
2132
2133 /// <summary>
2134 /// This is called from within simulate but outside the locked portion
2135 /// We need to do our own locking here
2136 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2137 ///
2138 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2139 /// that the space was using.
2140 /// </summary>
2141 /// <param name="prim"></param>
2142 public void RemovePrimThreadLocked(OdePrim prim)
2143 {
2144//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2145 lock (prim)
2146 {
2147 remCollisionEventReporting(prim);
2148 lock (ode)
2149 {
2150 if (prim.prim_geom != IntPtr.Zero)
2151 {
2152 prim.ResetTaints();
2153
2154 if (prim.IsPhysical)
2155 {
2156 prim.disableBody();
2157 if (prim.childPrim)
2158 {
2159 prim.childPrim = false;
2160 prim.Body = IntPtr.Zero;
2161 prim.m_disabled = true;
2162 prim.IsPhysical = false;
2163 }
2164
2165
2166 }
2167 // we don't want to remove the main space
2168
2169 // If the geometry is in the targetspace, remove it from the target space
2170 //m_log.Warn(prim.m_targetSpace);
2171
2172 //if (prim.m_targetSpace != IntPtr.Zero)
2173 //{
2174 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2175 //{
2176
2177 //if (d.GeomIsSpace(prim.m_targetSpace))
2178 //{
2179 //waitForSpaceUnlock(prim.m_targetSpace);
2180 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2181 prim.m_targetSpace = IntPtr.Zero;
2182 //}
2183 //else
2184 //{
2185 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2186 //((OdePrim)prim).m_targetSpace.ToString());
2187 //}
2188
2189 //}
2190 //}
2191 //m_log.Warn(prim.prim_geom);
2192 try
2193 {
2194 if (prim.prim_geom != IntPtr.Zero)
2195 {
2196
2197//string tPA;
2198//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2199//Console.WriteLine("**** Remove {0}", tPA);
2200 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2201 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2202 d.GeomDestroy(prim.prim_geom);
2203 prim.prim_geom = IntPtr.Zero;
2204 }
2205 else
2206 {
2207 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2208 }
2209 }
2210 catch (AccessViolationException)
2211 {
2212 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2213 }
2214 lock (_prims)
2215 _prims.Remove(prim);
2216
2217 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2218 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2219 //{
2220 //if (prim.m_targetSpace != null)
2221 //{
2222 //if (d.GeomIsSpace(prim.m_targetSpace))
2223 //{
2224 //waitForSpaceUnlock(prim.m_targetSpace);
2225 //d.SpaceRemove(space, prim.m_targetSpace);
2226 // free up memory used by the space.
2227 //d.SpaceDestroy(prim.m_targetSpace);
2228 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2229 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2230 //}
2231 //else
2232 //{
2233 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2234 //((OdePrim) prim).m_targetSpace.ToString());
2235 //}
2236 //}
2237 //}
2238
2239 if (SupportsNINJAJoints)
2240 {
2241 RemoveAllJointsConnectedToActorThreadLocked(prim);
2242 }
2243 }
2244 }
2245 }
2246 }
2247
2248 #endregion
2249
2250 #region Space Separation Calculation
2251
2252 /// <summary>
2253 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2254 /// </summary>
2255 /// <param name="pSpace"></param>
2256 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2257 {
2258 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2259 {
2260 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2261 {
2262 if (staticPrimspace[x, y] == pSpace)
2263 staticPrimspace[x, y] = IntPtr.Zero;
2264 }
2265 }
2266 }
2267
2268 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2269 {
2270 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2271 }
2272
2273 /// <summary>
2274 /// Called when a static prim moves. Allocates a space for the prim based on its position
2275 /// </summary>
2276 /// <param name="geom">the pointer to the geom that moved</param>
2277 /// <param name="pos">the position that the geom moved to</param>
2278 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2279 /// <returns>a pointer to the new space it's in</returns>
2280 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2281 {
2282 // Called from setting the Position and Size of an ODEPrim so
2283 // it's already in locked space.
2284
2285 // we don't want to remove the main space
2286 // we don't need to test physical here because this function should
2287 // never be called if the prim is physical(active)
2288
2289 // All physical prim end up in the root space
2290 //Thread.Sleep(20);
2291 if (currentspace != space)
2292 {
2293 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2294 //if (currentspace == IntPtr.Zero)
2295 //{
2296 //int adfadf = 0;
2297 //}
2298 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2299 {
2300 if (d.GeomIsSpace(currentspace))
2301 {
2302 waitForSpaceUnlock(currentspace);
2303 d.SpaceRemove(currentspace, geom);
2304 }
2305 else
2306 {
2307 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2308 " Geom:" + geom);
2309 }
2310 }
2311 else
2312 {
2313 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2314 if (sGeomIsIn != IntPtr.Zero)
2315 {
2316 if (d.GeomIsSpace(currentspace))
2317 {
2318 waitForSpaceUnlock(sGeomIsIn);
2319 d.SpaceRemove(sGeomIsIn, geom);
2320 }
2321 else
2322 {
2323 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2324 sGeomIsIn + " Geom:" + geom);
2325 }
2326 }
2327 }
2328
2329 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2330 if (d.SpaceGetNumGeoms(currentspace) == 0)
2331 {
2332 if (currentspace != IntPtr.Zero)
2333 {
2334 if (d.GeomIsSpace(currentspace))
2335 {
2336 waitForSpaceUnlock(currentspace);
2337 waitForSpaceUnlock(space);
2338 d.SpaceRemove(space, currentspace);
2339 // free up memory used by the space.
2340
2341 //d.SpaceDestroy(currentspace);
2342 resetSpaceArrayItemToZero(currentspace);
2343 }
2344 else
2345 {
2346 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2347 currentspace + " Geom:" + geom);
2348 }
2349 }
2350 }
2351 }
2352 else
2353 {
2354 // this is a physical object that got disabled. ;.;
2355 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2356 {
2357 if (d.SpaceQuery(currentspace, geom))
2358 {
2359 if (d.GeomIsSpace(currentspace))
2360 {
2361 waitForSpaceUnlock(currentspace);
2362 d.SpaceRemove(currentspace, geom);
2363 }
2364 else
2365 {
2366 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2367 currentspace + " Geom:" + geom);
2368 }
2369 }
2370 else
2371 {
2372 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2373 if (sGeomIsIn != IntPtr.Zero)
2374 {
2375 if (d.GeomIsSpace(sGeomIsIn))
2376 {
2377 waitForSpaceUnlock(sGeomIsIn);
2378 d.SpaceRemove(sGeomIsIn, geom);
2379 }
2380 else
2381 {
2382 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2383 sGeomIsIn + " Geom:" + geom);
2384 }
2385 }
2386 }
2387 }
2388 }
2389
2390 // The routines in the Position and Size sections do the 'inserting' into the space,
2391 // so all we have to do is make sure that the space that we're putting the prim into
2392 // is in the 'main' space.
2393 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2394 IntPtr newspace = calculateSpaceForGeom(pos);
2395
2396 if (newspace == IntPtr.Zero)
2397 {
2398 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2399 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2400 }
2401
2402 return newspace;
2403 }
2404
2405 /// <summary>
2406 /// Creates a new space at X Y
2407 /// </summary>
2408 /// <param name="iprimspaceArrItemX"></param>
2409 /// <param name="iprimspaceArrItemY"></param>
2410 /// <returns>A pointer to the created space</returns>
2411 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2412 {
2413 // creating a new space for prim and inserting it into main space.
2414 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2415 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2416 waitForSpaceUnlock(space);
2417 d.SpaceSetSublevel(space, 1);
2418 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2419 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2420 }
2421
2422 /// <summary>
2423 /// Calculates the space the prim should be in by its position
2424 /// </summary>
2425 /// <param name="pos"></param>
2426 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2427 public IntPtr calculateSpaceForGeom(Vector3 pos)
2428 {
2429 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2430 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2431 return staticPrimspace[xyspace[0], xyspace[1]];
2432 }
2433
2434 /// <summary>
2435 /// Holds the space allocation logic
2436 /// </summary>
2437 /// <param name="pos"></param>
2438 /// <returns>an array item based on the position</returns>
2439 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2440 {
2441 int[] returnint = new int[2];
2442
2443 returnint[0] = (int) (pos.X/metersInSpace);
2444
2445 if (returnint[0] > ((int) (259f/metersInSpace)))
2446 returnint[0] = ((int) (259f/metersInSpace));
2447 if (returnint[0] < 0)
2448 returnint[0] = 0;
2449
2450 returnint[1] = (int) (pos.Y/metersInSpace);
2451 if (returnint[1] > ((int) (259f/metersInSpace)))
2452 returnint[1] = ((int) (259f/metersInSpace));
2453 if (returnint[1] < 0)
2454 returnint[1] = 0;
2455
2456 return returnint;
2457 }
2458
2459 #endregion
2460
2461 /// <summary>
2462 /// Routine to figure out if we need to mesh this prim with our mesher
2463 /// </summary>
2464 /// <param name="pbs"></param>
2465 /// <returns></returns>
2466 public bool needsMeshing(PrimitiveBaseShape pbs)
2467 {
2468 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2469 // but we still need to check for sculptie meshing being enabled so this is the most
2470 // convenient place to do it for now...
2471
2472 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2473 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2474 int iPropertiesNotSupportedDefault = 0;
2475
2476 if (pbs.SculptEntry && !meshSculptedPrim)
2477 {
2478#if SPAM
2479 m_log.Warn("NonMesh");
2480#endif
2481 return false;
2482 }
2483
2484 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2485 if (!forceSimplePrimMeshing)
2486 {
2487 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2488 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2489 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2490 {
2491
2492 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2493 && pbs.ProfileHollow == 0
2494 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2495 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2496 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2497 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2498 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2499 {
2500#if SPAM
2501 m_log.Warn("NonMesh");
2502#endif
2503 return false;
2504 }
2505 }
2506 }
2507
2508 if (pbs.ProfileHollow != 0)
2509 iPropertiesNotSupportedDefault++;
2510
2511 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2512 iPropertiesNotSupportedDefault++;
2513
2514 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2515 iPropertiesNotSupportedDefault++;
2516
2517 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2518 iPropertiesNotSupportedDefault++;
2519
2520 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2521 iPropertiesNotSupportedDefault++;
2522
2523 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2524 iPropertiesNotSupportedDefault++;
2525
2526 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2527 iPropertiesNotSupportedDefault++;
2528
2529 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2530 iPropertiesNotSupportedDefault++;
2531
2532 // test for torus
2533 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2534 {
2535 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2536 {
2537 iPropertiesNotSupportedDefault++;
2538 }
2539 }
2540 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2541 {
2542 if (pbs.PathCurve == (byte)Extrusion.Straight)
2543 {
2544 iPropertiesNotSupportedDefault++;
2545 }
2546
2547 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2548 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2549 {
2550 iPropertiesNotSupportedDefault++;
2551 }
2552 }
2553 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2554 {
2555 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2556 {
2557 iPropertiesNotSupportedDefault++;
2558 }
2559 }
2560 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2561 {
2562 if (pbs.PathCurve == (byte)Extrusion.Straight)
2563 {
2564 iPropertiesNotSupportedDefault++;
2565 }
2566 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2567 {
2568 iPropertiesNotSupportedDefault++;
2569 }
2570 }
2571
2572
2573 if (iPropertiesNotSupportedDefault == 0)
2574 {
2575#if SPAM
2576 m_log.Warn("NonMesh");
2577#endif
2578 return false;
2579 }
2580#if SPAM
2581 m_log.Debug("Mesh");
2582#endif
2583 return true;
2584 }
2585
2586 /// <summary>
2587 /// Called after our prim properties are set Scale, position etc.
2588 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2589 /// This assures us that we have no race conditions
2590 /// </summary>
2591 /// <param name="prim"></param>
2592 public override void AddPhysicsActorTaint(PhysicsActor prim)
2593 {
2594
2595 if (prim is OdePrim)
2596 {
2597 OdePrim taintedprim = ((OdePrim) prim);
2598 lock (_taintedPrimLock)
2599 {
2600 if (!(_taintedPrimH.Contains(taintedprim)))
2601 {
2602//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2603 _taintedPrimH.Add(taintedprim); // HashSet for searching
2604 _taintedPrimL.Add(taintedprim); // List for ordered readout
2605 }
2606 }
2607 return;
2608 }
2609 else if (prim is OdeCharacter)
2610 {
2611 OdeCharacter taintedchar = ((OdeCharacter)prim);
2612 lock (_taintedActors)
2613 {
2614 if (!(_taintedActors.Contains(taintedchar)))
2615 {
2616 _taintedActors.Add(taintedchar);
2617 if (taintedchar.bad)
2618 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2619 }
2620 }
2621 }
2622 }
2623
2624 /// <summary>
2625 /// This is our main simulate loop
2626 /// It's thread locked by a Mutex in the scene.
2627 /// It holds Collisions, it instructs ODE to step through the physical reactions
2628 /// It moves the objects around in memory
2629 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2630 /// </summary>
2631 /// <param name="timeStep"></param>
2632 /// <returns></returns>
2633 public override float Simulate(float timeStep)
2634 {
2635 if (framecount >= int.MaxValue)
2636 framecount = 0;
2637 //if (m_worldOffset != Vector3.Zero)
2638 // return 0;
2639
2640 framecount++;
2641
2642 DateTime now = DateTime.UtcNow;
2643 TimeSpan SinceLastFrame = now - m_lastframe;
2644 m_lastframe = now;
2645 float realtime = (float)SinceLastFrame.TotalSeconds;
2646// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2647 timeStep = realtime;
2648
2649 // float fps = 1.0f / realtime;
2650 float fps = 0.0f; // number of ODE steps in this Simulate step
2651 //m_log.Info(timeStep.ToString());
2652 step_time += timeStep;
2653
2654 // If We're loaded down by something else,
2655 // or debugging with the Visual Studio project on pause
2656 // skip a few frames to catch up gracefully.
2657 // without shooting the physicsactors all over the place
2658
2659 if (step_time >= m_SkipFramesAtms)
2660 {
2661 // Instead of trying to catch up, it'll do 5 physics frames only
2662 step_time = ODE_STEPSIZE;
2663 m_physicsiterations = 5;
2664 }
2665 else
2666 {
2667 m_physicsiterations = 10;
2668 }
2669
2670 if (SupportsNINJAJoints)
2671 {
2672 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2673 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2674 }
2675
2676 lock (OdeLock)
2677 {
2678 // Process 10 frames if the sim is running normal..
2679 // process 5 frames if the sim is running slow
2680 //try
2681 //{
2682 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2683 //}
2684 //catch (StackOverflowException)
2685 //{
2686 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2687 // ode.drelease(world);
2688 //base.TriggerPhysicsBasedRestart();
2689 //}
2690
2691 int i = 0;
2692
2693 // Figure out the Frames Per Second we're going at.
2694 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2695
2696 // fps = (step_time / ODE_STEPSIZE) * 1000;
2697 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2698 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2699
2700 // step_time = 0.09375f;
2701
2702 while (step_time > 0.0f)
2703 {
2704 //lock (ode)
2705 //{
2706 //if (!ode.lockquery())
2707 //{
2708 // ode.dlock(world);
2709 try
2710 {
2711 // Insert, remove Characters
2712 bool processedtaints = false;
2713
2714 lock (_taintedActors)
2715 {
2716 if (_taintedActors.Count > 0)
2717 {
2718 foreach (OdeCharacter character in _taintedActors)
2719 {
2720
2721 character.ProcessTaints(ODE_STEPSIZE);
2722
2723 processedtaints = true;
2724 //character.m_collisionscore = 0;
2725 }
2726
2727 if (processedtaints)
2728 _taintedActors.Clear();
2729 }
2730 } // end lock _taintedActors
2731
2732 // Modify other objects in the scene.
2733 processedtaints = false;
2734
2735 lock (_taintedPrimLock)
2736 {
2737 foreach (OdePrim prim in _taintedPrimL)
2738 {
2739 if (prim.m_taintremove)
2740 {
2741 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2742 RemovePrimThreadLocked(prim);
2743 }
2744 else
2745 {
2746 //Console.WriteLine("Simulate calls ProcessTaints");
2747 prim.ProcessTaints(ODE_STEPSIZE);
2748 }
2749 processedtaints = true;
2750 prim.m_collisionscore = 0;
2751
2752 // This loop can block up the Heartbeat for a very long time on large regions.
2753 // We need to let the Watchdog know that the Heartbeat is not dead
2754 // NOTE: This is currently commented out, but if things like OAR loading are
2755 // timing the heartbeat out we will need to uncomment it
2756 //Watchdog.UpdateThread();
2757 }
2758
2759 if (SupportsNINJAJoints)
2760 {
2761 // Create pending joints, if possible
2762
2763 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2764 // a joint requires specifying the body id of both involved bodies
2765 if (pendingJoints.Count > 0)
2766 {
2767 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2768 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2769 foreach (PhysicsJoint joint in pendingJoints)
2770 {
2771 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2772 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2773 System.StringSplitOptions.RemoveEmptyEntries);
2774 List<IntPtr> jointBodies = new List<IntPtr>();
2775 bool allJointBodiesAreReady = true;
2776 foreach (string jointParam in jointParams)
2777 {
2778 if (jointParam == "NULL")
2779 {
2780 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2781 jointBodies.Add(IntPtr.Zero);
2782 }
2783 else
2784 {
2785 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2786 bool foundPrim = false;
2787 lock (_prims)
2788 {
2789 foreach (OdePrim prim in _prims) // FIXME: inefficient
2790 {
2791 if (prim.SOPName == jointParam)
2792 {
2793 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2794 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2795 {
2796 jointBodies.Add(prim.Body);
2797 foundPrim = true;
2798 break;
2799 }
2800 else
2801 {
2802 DoJointErrorMessage(joint, "prim name " + jointParam +
2803 " exists but is not (yet) physical; deferring joint creation. " +
2804 "IsPhysical property is " + prim.IsPhysical +
2805 " and body is " + prim.Body);
2806 foundPrim = false;
2807 break;
2808 }
2809 }
2810 }
2811 }
2812 if (foundPrim)
2813 {
2814 // all is fine
2815 }
2816 else
2817 {
2818 allJointBodiesAreReady = false;
2819 break;
2820 }
2821 }
2822 }
2823 if (allJointBodiesAreReady)
2824 {
2825 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2826 if (jointBodies[0] == jointBodies[1])
2827 {
2828 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2829 }
2830 else
2831 {
2832 switch (joint.Type)
2833 {
2834 case PhysicsJointType.Ball:
2835 {
2836 IntPtr odeJoint;
2837 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2838 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2839 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2840 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2841 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2842 d.JointSetBallAnchor(odeJoint,
2843 joint.Position.X,
2844 joint.Position.Y,
2845 joint.Position.Z);
2846 //DoJointErrorMessage(joint, "ODE joint setting OK");
2847 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2848 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2849 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2850 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2851
2852 if (joint is OdePhysicsJoint)
2853 {
2854 ((OdePhysicsJoint)joint).jointID = odeJoint;
2855 }
2856 else
2857 {
2858 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2859 }
2860 }
2861 break;
2862 case PhysicsJointType.Hinge:
2863 {
2864 IntPtr odeJoint;
2865 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2866 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2867 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2868 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2869 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2870 d.JointSetHingeAnchor(odeJoint,
2871 joint.Position.X,
2872 joint.Position.Y,
2873 joint.Position.Z);
2874 // We use the orientation of the x-axis of the joint's coordinate frame
2875 // as the axis for the hinge.
2876
2877 // Therefore, we must get the joint's coordinate frame based on the
2878 // joint.Rotation field, which originates from the orientation of the
2879 // joint's proxy object in the scene.
2880
2881 // The joint's coordinate frame is defined as the transformation matrix
2882 // that converts a vector from joint-local coordinates into world coordinates.
2883 // World coordinates are defined as the XYZ coordinate system of the sim,
2884 // as shown in the top status-bar of the viewer.
2885
2886 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2887 // and use that as the hinge axis.
2888
2889 //joint.Rotation.Normalize();
2890 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2891
2892 // Now extract the X axis of the joint's coordinate frame.
2893
2894 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2895 // tar pit of transposed, inverted, and generally messed-up orientations.
2896 // (In other words, Matrix4.AtAxis() is borked.)
2897 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2898
2899 // Instead, compute the X axis of the coordinate frame by transforming
2900 // the (1,0,0) vector. At least that works.
2901
2902 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2903 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2904 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2905 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2906 d.JointSetHingeAxis(odeJoint,
2907 jointAxis.X,
2908 jointAxis.Y,
2909 jointAxis.Z);
2910 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2911 if (joint is OdePhysicsJoint)
2912 {
2913 ((OdePhysicsJoint)joint).jointID = odeJoint;
2914 }
2915 else
2916 {
2917 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2918 }
2919 }
2920 break;
2921 }
2922 successfullyProcessedPendingJoints.Add(joint);
2923 }
2924 }
2925 else
2926 {
2927 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2928 }
2929 }
2930 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2931 {
2932 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2933 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2934 InternalRemovePendingJoint(successfullyProcessedJoint);
2935 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2936 InternalAddActiveJoint(successfullyProcessedJoint);
2937 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2938 }
2939 }
2940 } // end SupportsNINJAJoints
2941
2942 if (processedtaints)
2943//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2944 _taintedPrimH.Clear(); // ??? if this only ???
2945 _taintedPrimL.Clear();
2946 } // end lock _taintedPrimLock
2947
2948 // Move characters
2949 lock (_characters)
2950 {
2951 List<OdeCharacter> defects = new List<OdeCharacter>();
2952 foreach (OdeCharacter actor in _characters)
2953 {
2954 if (actor != null)
2955 actor.Move(ODE_STEPSIZE, defects);
2956 }
2957 if (0 != defects.Count)
2958 {
2959 foreach (OdeCharacter defect in defects)
2960 {
2961 RemoveCharacter(defect);
2962 }
2963 }
2964 } // end lock _characters
2965
2966 // Move other active objects
2967 lock (_activeprims)
2968 {
2969 foreach (OdePrim prim in _activeprims)
2970 {
2971 prim.m_collisionscore = 0;
2972 prim.Move(ODE_STEPSIZE);
2973 }
2974 } // end lock _activeprims
2975
2976 //if ((framecount % m_randomizeWater) == 0)
2977 // randomizeWater(waterlevel);
2978
2979 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2980 m_rayCastManager.ProcessQueuedRequests();
2981
2982 collision_optimized(ODE_STEPSIZE);
2983
2984 lock (_collisionEventPrim)
2985 {
2986 foreach (PhysicsActor obj in _collisionEventPrim)
2987 {
2988 if (obj == null)
2989 continue;
2990
2991 switch ((ActorTypes)obj.PhysicsActorType)
2992 {
2993 case ActorTypes.Agent:
2994 OdeCharacter cobj = (OdeCharacter)obj;
2995 cobj.AddCollisionFrameTime(100);
2996 cobj.SendCollisions();
2997 break;
2998 case ActorTypes.Prim:
2999 OdePrim pobj = (OdePrim)obj;
3000 pobj.SendCollisions();
3001 break;
3002 }
3003 }
3004 } // end lock _collisionEventPrim
3005
3006 //if (m_global_contactcount > 5)
3007 //{
3008 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3009 //}
3010
3011 m_global_contactcount = 0;
3012
3013 d.WorldQuickStep(world, ODE_STEPSIZE);
3014 d.JointGroupEmpty(contactgroup);
3015 fps++;
3016 //ode.dunlock(world);
3017 } // end try
3018 catch (Exception e)
3019 {
3020 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3021 ode.dunlock(world);
3022 }
3023
3024 step_time -= ODE_STEPSIZE;
3025 i++;
3026 //}
3027 //else
3028 //{
3029 //fps = 0;
3030 //}
3031 //}
3032 } // end while (step_time > 0.0f)
3033
3034 lock (_characters)
3035 {
3036 foreach (OdeCharacter actor in _characters)
3037 {
3038 if (actor != null)
3039 {
3040 if (actor.bad)
3041 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3042 actor.UpdatePositionAndVelocity();
3043 }
3044 }
3045 }
3046
3047 lock (_badCharacter)
3048 {
3049 if (_badCharacter.Count > 0)
3050 {
3051 foreach (OdeCharacter chr in _badCharacter)
3052 {
3053 RemoveCharacter(chr);
3054 }
3055 _badCharacter.Clear();
3056 }
3057 }
3058
3059 lock (_activeprims)
3060 {
3061 //if (timeStep < 0.2f)
3062 {
3063 foreach (OdePrim actor in _activeprims)
3064 {
3065 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3066 {
3067 actor.UpdatePositionAndVelocity();
3068
3069 if (SupportsNINJAJoints)
3070 {
3071 // If an actor moved, move its joint proxy objects as well.
3072 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3073 // for this purpose but it is never called! So we just do the joint
3074 // movement code here.
3075
3076 if (actor.SOPName != null &&
3077 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3078 joints_connecting_actor[actor.SOPName] != null &&
3079 joints_connecting_actor[actor.SOPName].Count > 0)
3080 {
3081 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3082 {
3083 if (affectedJoint.IsInPhysicsEngine)
3084 {
3085 DoJointMoved(affectedJoint);
3086 }
3087 else
3088 {
3089 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3090 }
3091 }
3092 }
3093 }
3094 }
3095 }
3096 }
3097 } // end lock _activeprims
3098
3099 //DumpJointInfo();
3100
3101 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3102 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3103 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3104 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3105 {
3106 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3107 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3108
3109 if (physics_logging_append_existing_logfile)
3110 {
3111 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3112 TextWriter fwriter = File.AppendText(fname);
3113 fwriter.WriteLine(header);
3114 fwriter.Close();
3115 }
3116 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3117 }
3118 } // end lock OdeLock
3119
3120 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3121 } // end Simulate
3122
3123 public override void GetResults()
3124 {
3125 }
3126
3127 public override bool IsThreaded
3128 {
3129 // for now we won't be multithreaded
3130 get { return (false); }
3131 }
3132
3133 #region ODE Specific Terrain Fixes
3134 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3135 {
3136 float[] returnarr = new float[262144];
3137 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3138
3139 // Filling out the array into its multi-dimensional components
3140 for (int y = 0; y < WorldExtents.Y; y++)
3141 {
3142 for (int x = 0; x < WorldExtents.X; x++)
3143 {
3144 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3145 }
3146 }
3147
3148 // Resize using Nearest Neighbour
3149
3150 // This particular way is quick but it only works on a multiple of the original
3151
3152 // The idea behind this method can be described with the following diagrams
3153 // second pass and third pass happen in the same loop really.. just separated
3154 // them to show what this does.
3155
3156 // First Pass
3157 // ResultArr:
3158 // 1,1,1,1,1,1
3159 // 1,1,1,1,1,1
3160 // 1,1,1,1,1,1
3161 // 1,1,1,1,1,1
3162 // 1,1,1,1,1,1
3163 // 1,1,1,1,1,1
3164
3165 // Second Pass
3166 // ResultArr2:
3167 // 1,,1,,1,,1,,1,,1,
3168 // ,,,,,,,,,,
3169 // 1,,1,,1,,1,,1,,1,
3170 // ,,,,,,,,,,
3171 // 1,,1,,1,,1,,1,,1,
3172 // ,,,,,,,,,,
3173 // 1,,1,,1,,1,,1,,1,
3174 // ,,,,,,,,,,
3175 // 1,,1,,1,,1,,1,,1,
3176 // ,,,,,,,,,,
3177 // 1,,1,,1,,1,,1,,1,
3178
3179 // Third pass fills in the blanks
3180 // ResultArr2:
3181 // 1,1,1,1,1,1,1,1,1,1,1,1
3182 // 1,1,1,1,1,1,1,1,1,1,1,1
3183 // 1,1,1,1,1,1,1,1,1,1,1,1
3184 // 1,1,1,1,1,1,1,1,1,1,1,1
3185 // 1,1,1,1,1,1,1,1,1,1,1,1
3186 // 1,1,1,1,1,1,1,1,1,1,1,1
3187 // 1,1,1,1,1,1,1,1,1,1,1,1
3188 // 1,1,1,1,1,1,1,1,1,1,1,1
3189 // 1,1,1,1,1,1,1,1,1,1,1,1
3190 // 1,1,1,1,1,1,1,1,1,1,1,1
3191 // 1,1,1,1,1,1,1,1,1,1,1,1
3192
3193 // X,Y = .
3194 // X+1,y = ^
3195 // X,Y+1 = *
3196 // X+1,Y+1 = #
3197
3198 // Filling in like this;
3199 // .*
3200 // ^#
3201 // 1st .
3202 // 2nd *
3203 // 3rd ^
3204 // 4th #
3205 // on single loop.
3206
3207 float[,] resultarr2 = new float[512, 512];
3208 for (int y = 0; y < WorldExtents.Y; y++)
3209 {
3210 for (int x = 0; x < WorldExtents.X; x++)
3211 {
3212 resultarr2[y * 2, x * 2] = resultarr[y, x];
3213
3214 if (y < WorldExtents.Y)
3215 {
3216 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3217 }
3218 if (x < WorldExtents.X)
3219 {
3220 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3221 }
3222 if (x < WorldExtents.X && y < WorldExtents.Y)
3223 {
3224 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3225 }
3226 }
3227 }
3228
3229 //Flatten out the array
3230 int i = 0;
3231 for (int y = 0; y < 512; y++)
3232 {
3233 for (int x = 0; x < 512; x++)
3234 {
3235 if (resultarr2[y, x] <= 0)
3236 returnarr[i] = 0.0000001f;
3237 else
3238 returnarr[i] = resultarr2[y, x];
3239
3240 i++;
3241 }
3242 }
3243
3244 return returnarr;
3245 }
3246
3247 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3248 {
3249 float[] returnarr = new float[262144];
3250 float[,] resultarr = new float[512,512];
3251
3252 // Filling out the array into its multi-dimensional components
3253 for (int y = 0; y < 256; y++)
3254 {
3255 for (int x = 0; x < 256; x++)
3256 {
3257 resultarr[y, x] = heightMap[y * 256 + x];
3258 }
3259 }
3260
3261 // Resize using interpolation
3262
3263 // This particular way is quick but it only works on a multiple of the original
3264
3265 // The idea behind this method can be described with the following diagrams
3266 // second pass and third pass happen in the same loop really.. just separated
3267 // them to show what this does.
3268
3269 // First Pass
3270 // ResultArr:
3271 // 1,1,1,1,1,1
3272 // 1,1,1,1,1,1
3273 // 1,1,1,1,1,1
3274 // 1,1,1,1,1,1
3275 // 1,1,1,1,1,1
3276 // 1,1,1,1,1,1
3277
3278 // Second Pass
3279 // ResultArr2:
3280 // 1,,1,,1,,1,,1,,1,
3281 // ,,,,,,,,,,
3282 // 1,,1,,1,,1,,1,,1,
3283 // ,,,,,,,,,,
3284 // 1,,1,,1,,1,,1,,1,
3285 // ,,,,,,,,,,
3286 // 1,,1,,1,,1,,1,,1,
3287 // ,,,,,,,,,,
3288 // 1,,1,,1,,1,,1,,1,
3289 // ,,,,,,,,,,
3290 // 1,,1,,1,,1,,1,,1,
3291
3292 // Third pass fills in the blanks
3293 // ResultArr2:
3294 // 1,1,1,1,1,1,1,1,1,1,1,1
3295 // 1,1,1,1,1,1,1,1,1,1,1,1
3296 // 1,1,1,1,1,1,1,1,1,1,1,1
3297 // 1,1,1,1,1,1,1,1,1,1,1,1
3298 // 1,1,1,1,1,1,1,1,1,1,1,1
3299 // 1,1,1,1,1,1,1,1,1,1,1,1
3300 // 1,1,1,1,1,1,1,1,1,1,1,1
3301 // 1,1,1,1,1,1,1,1,1,1,1,1
3302 // 1,1,1,1,1,1,1,1,1,1,1,1
3303 // 1,1,1,1,1,1,1,1,1,1,1,1
3304 // 1,1,1,1,1,1,1,1,1,1,1,1
3305
3306 // X,Y = .
3307 // X+1,y = ^
3308 // X,Y+1 = *
3309 // X+1,Y+1 = #
3310
3311 // Filling in like this;
3312 // .*
3313 // ^#
3314 // 1st .
3315 // 2nd *
3316 // 3rd ^
3317 // 4th #
3318 // on single loop.
3319
3320 float[,] resultarr2 = new float[512,512];
3321 for (int y = 0; y < (int)Constants.RegionSize; y++)
3322 {
3323 for (int x = 0; x < (int)Constants.RegionSize; x++)
3324 {
3325 resultarr2[y*2, x*2] = resultarr[y, x];
3326
3327 if (y < (int)Constants.RegionSize)
3328 {
3329 if (y + 1 < (int)Constants.RegionSize)
3330 {
3331 if (x + 1 < (int)Constants.RegionSize)
3332 {
3333 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3334 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3335 }
3336 else
3337 {
3338 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3339 }
3340 }
3341 else
3342 {
3343 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3344 }
3345 }
3346 if (x < (int)Constants.RegionSize)
3347 {
3348 if (x + 1 < (int)Constants.RegionSize)
3349 {
3350 if (y + 1 < (int)Constants.RegionSize)
3351 {
3352 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3353 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3354 }
3355 else
3356 {
3357 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3358 }
3359 }
3360 else
3361 {
3362 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3363 }
3364 }
3365 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3366 {
3367 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3368 {
3369 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3370 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3371 }
3372 else
3373 {
3374 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3375 }
3376 }
3377 }
3378 }
3379 //Flatten out the array
3380 int i = 0;
3381 for (int y = 0; y < 512; y++)
3382 {
3383 for (int x = 0; x < 512; x++)
3384 {
3385 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3386 {
3387 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3388 resultarr2[y, x] = 0;
3389 }
3390 returnarr[i] = resultarr2[y, x];
3391 i++;
3392 }
3393 }
3394
3395 return returnarr;
3396 }
3397
3398 #endregion
3399
3400 public override void SetTerrain(float[] heightMap)
3401 {
3402 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3403 {
3404 if (m_parentScene is OdeScene)
3405 {
3406 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3407 }
3408 }
3409 else
3410 {
3411 SetTerrain(heightMap, m_worldOffset);
3412 }
3413 }
3414
3415 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3416 {
3417
3418 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3419
3420 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3421 uint heightmapHeight = regionsize + 1;
3422
3423 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3424 uint heightmapHeightSamples = (uint)regionsize + 2;
3425
3426 // Array of height samples for ODE
3427 float[] _heightmap;
3428 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3429
3430 // Other ODE parameters
3431 const float scale = 1.0f;
3432 const float offset = 0.0f;
3433 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3434 const int wrap = 0;
3435
3436 float hfmin = 2000f;
3437 float hfmax = -2000f;
3438 float minele = 0.0f; // Dont allow -ve heights
3439
3440 uint x = 0;
3441 uint y = 0;
3442 uint xx = 0;
3443 uint yy = 0;
3444
3445 // load the height samples array from the heightMap
3446 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3447 {
3448 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3449 {
3450 xx = x - 1;
3451 if (xx < 0) xx = 0;
3452 if (xx > (regionsize - 1)) xx = regionsize - 1;
3453
3454 yy = y - 1;
3455 if (yy < 0) yy = 0;
3456 if (yy > (regionsize - 1)) yy = regionsize - 1;
3457 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3458 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3459 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3460 if (val < minele) val = minele;
3461 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3462 hfmin = (val < hfmin) ? val : hfmin;
3463 hfmax = (val > hfmax) ? val : hfmax;
3464 }
3465 }
3466
3467 lock (OdeLock)
3468 {
3469 IntPtr GroundGeom = IntPtr.Zero;
3470 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3471 {
3472 RegionTerrain.Remove(pOffset);
3473 if (GroundGeom != IntPtr.Zero)
3474 {
3475 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3476 {
3477 TerrainHeightFieldHeights.Remove(GroundGeom);
3478 }
3479 d.SpaceRemove(space, GroundGeom);
3480 d.GeomDestroy(GroundGeom);
3481 }
3482 }
3483 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3484 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3485 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3486 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3487 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3488 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3489 if (GroundGeom != IntPtr.Zero)
3490 {
3491 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3492 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3493 }
3494 geom_name_map[GroundGeom] = "Terrain";
3495
3496 d.Matrix3 R = new d.Matrix3();
3497
3498 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3499 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3500 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3501
3502 q1 = q1 * q2;
3503 //q1 = q1 * q3;
3504 Vector3 v3;
3505 float angle;
3506 q1.GetAxisAngle(out v3, out angle);
3507
3508 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3509 d.GeomSetRotation(GroundGeom, ref R);
3510 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3511 IntPtr testGround = IntPtr.Zero;
3512 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3513 {
3514 RegionTerrain.Remove(pOffset);
3515 }
3516 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3517 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3518 }
3519 }
3520
3521 public override void DeleteTerrain()
3522 {
3523 }
3524
3525 public float GetWaterLevel()
3526 {
3527 return waterlevel;
3528 }
3529
3530 public override bool SupportsCombining()
3531 {
3532 return true;
3533 }
3534
3535 public override void UnCombine(PhysicsScene pScene)
3536 {
3537 IntPtr localGround = IntPtr.Zero;
3538// float[] localHeightfield;
3539 bool proceed = false;
3540 List<IntPtr> geomDestroyList = new List<IntPtr>();
3541
3542 lock (OdeLock)
3543 {
3544 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3545 {
3546 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3547 {
3548 if (geom == localGround)
3549 {
3550// localHeightfield = TerrainHeightFieldHeights[geom];
3551 proceed = true;
3552 }
3553 else
3554 {
3555 geomDestroyList.Add(geom);
3556 }
3557 }
3558
3559 if (proceed)
3560 {
3561 m_worldOffset = Vector3.Zero;
3562 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3563 m_parentScene = null;
3564
3565 foreach (IntPtr g in geomDestroyList)
3566 {
3567 // removingHeightField needs to be done or the garbage collector will
3568 // collect the terrain data before we tell ODE to destroy it causing
3569 // memory corruption
3570 if (TerrainHeightFieldHeights.ContainsKey(g))
3571 {
3572// float[] removingHeightField = TerrainHeightFieldHeights[g];
3573 TerrainHeightFieldHeights.Remove(g);
3574
3575 if (RegionTerrain.ContainsKey(g))
3576 {
3577 RegionTerrain.Remove(g);
3578 }
3579
3580 d.GeomDestroy(g);
3581 //removingHeightField = new float[0];
3582 }
3583 }
3584
3585 }
3586 else
3587 {
3588 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3589
3590 }
3591 }
3592 }
3593 }
3594
3595 public override void SetWaterLevel(float baseheight)
3596 {
3597 waterlevel = baseheight;
3598 randomizeWater(waterlevel);
3599 }
3600
3601 public void randomizeWater(float baseheight)
3602 {
3603 const uint heightmapWidth = m_regionWidth + 2;
3604 const uint heightmapHeight = m_regionHeight + 2;
3605 const uint heightmapWidthSamples = m_regionWidth + 2;
3606 const uint heightmapHeightSamples = m_regionHeight + 2;
3607 const float scale = 1.0f;
3608 const float offset = 0.0f;
3609 const float thickness = 2.9f;
3610 const int wrap = 0;
3611
3612 for (int i = 0; i < (258 * 258); i++)
3613 {
3614 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3615 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3616 }
3617
3618 lock (OdeLock)
3619 {
3620 if (WaterGeom != IntPtr.Zero)
3621 {
3622 d.SpaceRemove(space, WaterGeom);
3623 }
3624 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3625 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3626 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3627 offset, thickness, wrap);
3628 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3629 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3630 if (WaterGeom != IntPtr.Zero)
3631 {
3632 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3633 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3634
3635 }
3636 geom_name_map[WaterGeom] = "Water";
3637
3638 d.Matrix3 R = new d.Matrix3();
3639
3640 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3641 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3642 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3643
3644 q1 = q1 * q2;
3645 //q1 = q1 * q3;
3646 Vector3 v3;
3647 float angle;
3648 q1.GetAxisAngle(out v3, out angle);
3649
3650 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3651 d.GeomSetRotation(WaterGeom, ref R);
3652 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3653
3654 }
3655
3656 }
3657
3658 public override void Dispose()
3659 {
3660 m_rayCastManager.Dispose();
3661 m_rayCastManager = null;
3662
3663 lock (OdeLock)
3664 {
3665 lock (_prims)
3666 {
3667 foreach (OdePrim prm in _prims)
3668 {
3669 RemovePrim(prm);
3670 }
3671 }
3672
3673 //foreach (OdeCharacter act in _characters)
3674 //{
3675 //RemoveAvatar(act);
3676 //}
3677 d.WorldDestroy(world);
3678 //d.CloseODE();
3679 }
3680 }
3681 public override Dictionary<uint, float> GetTopColliders()
3682 {
3683 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3684 int cnt = 0;
3685 lock (_prims)
3686 {
3687 foreach (OdePrim prm in _prims)
3688 {
3689 if (prm.CollisionScore > 0)
3690 {
3691 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3692 cnt++;
3693 prm.CollisionScore = 0f;
3694 if (cnt > 25)
3695 {
3696 break;
3697 }
3698 }
3699 }
3700 }
3701 return returncolliders;
3702 }
3703
3704 public override bool SupportsRayCast()
3705 {
3706 return true;
3707 }
3708
3709 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3710 {
3711 if (retMethod != null)
3712 {
3713 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3714 }
3715 }
3716
3717#if USE_DRAWSTUFF
3718 // Keyboard callback
3719 public void command(int cmd)
3720 {
3721 IntPtr geom;
3722 d.Mass mass;
3723 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3724
3725
3726
3727 Char ch = Char.ToLower((Char)cmd);
3728 switch ((Char)ch)
3729 {
3730 case 'w':
3731 try
3732 {
3733 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3734
3735 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3736 ds.SetViewpoint(ref xyz, ref hpr);
3737 }
3738 catch (ArgumentException)
3739 { hpr.X = 0; }
3740 break;
3741
3742 case 'a':
3743 hpr.X++;
3744 ds.SetViewpoint(ref xyz, ref hpr);
3745 break;
3746
3747 case 's':
3748 try
3749 {
3750 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3751
3752 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3753 ds.SetViewpoint(ref xyz, ref hpr);
3754 }
3755 catch (ArgumentException)
3756 { hpr.X = 0; }
3757 break;
3758 case 'd':
3759 hpr.X--;
3760 ds.SetViewpoint(ref xyz, ref hpr);
3761 break;
3762 case 'r':
3763 xyz.Z++;
3764 ds.SetViewpoint(ref xyz, ref hpr);
3765 break;
3766 case 'f':
3767 xyz.Z--;
3768 ds.SetViewpoint(ref xyz, ref hpr);
3769 break;
3770 case 'e':
3771 xyz.Y++;
3772 ds.SetViewpoint(ref xyz, ref hpr);
3773 break;
3774 case 'q':
3775 xyz.Y--;
3776 ds.SetViewpoint(ref xyz, ref hpr);
3777 break;
3778 }
3779 }
3780
3781 public void step(int pause)
3782 {
3783
3784 ds.SetColor(1.0f, 1.0f, 0.0f);
3785 ds.SetTexture(ds.Texture.Wood);
3786 lock (_prims)
3787 {
3788 foreach (OdePrim prm in _prims)
3789 {
3790 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3791 if (prm.prim_geom != IntPtr.Zero)
3792 {
3793 d.Vector3 pos;
3794 d.GeomCopyPosition(prm.prim_geom, out pos);
3795 //d.BodyCopyPosition(body, out pos);
3796
3797 d.Matrix3 R;
3798 d.GeomCopyRotation(prm.prim_geom, out R);
3799 //d.BodyCopyRotation(body, out R);
3800
3801
3802 d.Vector3 sides = new d.Vector3();
3803 sides.X = prm.Size.X;
3804 sides.Y = prm.Size.Y;
3805 sides.Z = prm.Size.Z;
3806
3807 ds.DrawBox(ref pos, ref R, ref sides);
3808 }
3809 }
3810 }
3811 ds.SetColor(1.0f, 0.0f, 0.0f);
3812 lock (_characters)
3813 {
3814 foreach (OdeCharacter chr in _characters)
3815 {
3816 if (chr.Shell != IntPtr.Zero)
3817 {
3818 IntPtr body = d.GeomGetBody(chr.Shell);
3819
3820 d.Vector3 pos;
3821 d.GeomCopyPosition(chr.Shell, out pos);
3822 //d.BodyCopyPosition(body, out pos);
3823
3824 d.Matrix3 R;
3825 d.GeomCopyRotation(chr.Shell, out R);
3826 //d.BodyCopyRotation(body, out R);
3827
3828 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3829 d.Vector3 sides = new d.Vector3();
3830 sides.X = 0.5f;
3831 sides.Y = 0.5f;
3832 sides.Z = 0.5f;
3833
3834 ds.DrawBox(ref pos, ref R, ref sides);
3835 }
3836 }
3837 }
3838 }
3839
3840 public void start(int unused)
3841 {
3842 ds.SetViewpoint(ref xyz, ref hpr);
3843 }
3844#endif
3845 }
3846}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
new file mode 100644
index 0000000..69e2d03
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
@@ -0,0 +1,122 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using log4net;
35using System.Reflection;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 [TestFixture]
40 public class ODETestClass
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private OdePlugin cbt;
45 private PhysicsScene ps;
46 private IMeshingPlugin imp;
47
48 [SetUp]
49 public void Initialize()
50 {
51 // Loading ODEPlugin
52 cbt = new OdePlugin();
53 // Loading Zero Mesher
54 imp = new ZeroMesherPlugin();
55 // Getting Physics Scene
56 ps = cbt.GetScene("test");
57 // Initializing Physics Scene.
58 ps.Initialise(imp.GetMesher(),null);
59 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
60 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
61 {
62 _heightmap[i] = 21f;
63 }
64 ps.SetTerrain(_heightmap);
65 }
66
67 [TearDown]
68 public void Terminate()
69 {
70 ps.DeleteTerrain();
71 ps.Dispose();
72
73 }
74
75 [Test]
76 public void CreateAndDropPhysicalCube()
77 {
78 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
79 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
80 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
81 Quaternion rot = Quaternion.Identity;
82 PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true);
83 OdePrim oprim = (OdePrim)prim;
84 OdeScene pscene = (OdeScene) ps;
85
86 Assert.That(oprim.m_taintadd);
87
88 prim.LocalID = 5;
89
90 for (int i = 0; i < 58; i++)
91 {
92 ps.Simulate(0.133f);
93
94 Assert.That(oprim.prim_geom != (IntPtr)0);
95
96 Assert.That(oprim.m_targetSpace != (IntPtr)0);
97
98 //Assert.That(oprim.m_targetSpace == pscene.space);
99 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
100
101 Assert.That(!oprim.m_taintadd);
102 m_log.Info("Prim Position (" + oprim.m_localID + "): " + prim.Position.ToString());
103
104 // Make sure we're above the ground
105 //Assert.That(prim.Position.Z > 20f);
106 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
107
108 // Make sure we've got a Body
109 Assert.That(oprim.Body != (IntPtr)0);
110 //m_log.Info(
111 }
112
113 // Make sure we're not somewhere above the ground
114 Assert.That(prim.Position.Z < 21.5f);
115
116 ps.RemovePrim(prim);
117 Assert.That(oprim.m_taintremove);
118 ps.Simulate(0.133f);
119 Assert.That(oprim.Body == (IntPtr)0);
120 }
121 }
122}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
new file mode 100644
index 0000000..87ca446
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
@@ -0,0 +1,98 @@
1/*
2 * Copyright ODE
3 * Ode.NET - .NET bindings for ODE
4 * Jason Perkins (starkos@industriousone.com)
5 * Licensed under the New BSD
6 * Part of the OpenDynamicsEngine
7Open Dynamics Engine
8Copyright (c) 2001-2007, Russell L. Smith.
9All rights reserved.
10
11Redistribution and use in source and binary forms, with or without
12modification, are permitted provided that the following conditions
13are met:
14
15Redistributions of source code must retain the above copyright notice,
16this list of conditions and the following disclaimer.
17
18Redistributions in binary form must reproduce the above copyright notice,
19this list of conditions and the following disclaimer in the documentation
20and/or other materials provided with the distribution.
21
22Neither the names of ODE's copyright owner nor the names of its
23contributors may be used to endorse or promote products derived from
24this software without specific prior written permission.
25
26THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 *
39 */
40
41using System;
42using System.Runtime.InteropServices;
43using Ode.NET;
44
45namespace Drawstuff.NET
46{
47#if dDOUBLE
48 using dReal = System.Double;
49#else
50 using dReal = System.Single;
51#endif
52
53 public static class ds
54 {
55 public const int VERSION = 2;
56
57 public enum Texture
58 {
59 None,
60 Wood
61 }
62
63 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
64 public delegate void CallbackFunction(int arg);
65
66 [StructLayout(LayoutKind.Sequential)]
67 public struct Functions
68 {
69 public int version;
70 public CallbackFunction start;
71 public CallbackFunction step;
72 public CallbackFunction command;
73 public CallbackFunction stop;
74 public string path_to_textures;
75 }
76
77 [DllImport("drawstuff", EntryPoint = "dsDrawBox")]
78 public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides);
79
80 [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")]
81 public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius);
82
83 [DllImport("drawstuff", EntryPoint = "dsDrawConvex")]
84 public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);
85
86 [DllImport("drawstuff", EntryPoint = "dsSetColor")]
87 public static extern void SetColor(float red, float green, float blue);
88
89 [DllImport("drawstuff", EntryPoint = "dsSetTexture")]
90 public static extern void SetTexture(Texture texture);
91
92 [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")]
93 public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr);
94
95 [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")]
96 public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn);
97 }
98}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index 6b74e74..0e7dd81 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -1215,7 +1215,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1215 1215
1216 public override float APIDDamping{ set { return; } } 1216 public override float APIDDamping{ set { return; } }
1217 1217
1218
1219 public override void SubscribeEvents(int ms) 1218 public override void SubscribeEvents(int ms)
1220 { 1219 {
1221 m_requestedUpdateFrequency = ms; 1220 m_requestedUpdateFrequency = ms;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index c91658e..243e2d7 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -572,8 +572,8 @@ namespace OpenSim.Region.Physics.OdePlugin
572 break; 572 break;
573 573
574 case HollowShape.Circle: 574 case HollowShape.Circle:
575 // Hollow shape is a perfect cyllinder in respect to the cube's scale 575 // Hollow shape is a perfect cylinder in respect to the cube's scale
576 // Cyllinder hollow volume calculation 576 // Cylinder hollow volume calculation
577 577
578 hollowVolume *= 0.1963495f * 3.07920140172638f; 578 hollowVolume *= 0.1963495f * 3.07920140172638f;
579 break; 579 break;
@@ -2819,7 +2819,7 @@ Console.WriteLine(" JointCreateFixed");
2819 } 2819 }
2820 public override bool PIDActive { set { m_usePID = value; } } 2820 public override bool PIDActive { set { m_usePID = value; } }
2821 public override float PIDTau { set { m_PIDTau = value; } } 2821 public override float PIDTau { set { m_PIDTau = value; } }
2822 2822
2823 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } 2823 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2824 public override bool PIDHoverActive { set { m_useHoverPID = value; } } 2824 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2825 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } 2825 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
index 91ec3df..9ba5ebb 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Physics.POSPlugin
301 { 301 {
302 set { return; } 302 set { return; }
303 } 303 }
304 304
305 public override Quaternion APIDTarget 305 public override Quaternion APIDTarget
306 { 306 {
307 set { return; } 307 set { return; }
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 4a24c7d..3edc3a2 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -88,89 +88,7 @@ namespace OpenSim.Region.RegionCombinerModule
88 public void RegionLoaded(Scene scene) 88 public void RegionLoaded(Scene scene)
89 { 89 {
90 if (enabledYN) 90 if (enabledYN)
91 {
92 RegionLoadedDoWork(scene); 91 RegionLoadedDoWork(scene);
93
94 scene.EventManager.OnNewPresence += NewPresence;
95 }
96 }
97
98 private void NewPresence(ScenePresence presence)
99 {
100 if (presence.IsChildAgent)
101 {
102 byte[] throttleData;
103
104 try
105 {
106 throttleData = presence.ControllingClient.GetThrottlesPacked(1);
107 }
108 catch (NotImplementedException)
109 {
110 return;
111 }
112
113 if (throttleData == null)
114 return;
115
116 if (throttleData.Length == 0)
117 return;
118
119 if (throttleData.Length != 28)
120 return;
121
122 byte[] adjData;
123 int pos = 0;
124
125 if (!BitConverter.IsLittleEndian)
126 {
127 byte[] newData = new byte[7 * 4];
128 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
129
130 for (int i = 0; i < 7; i++)
131 Array.Reverse(newData, i * 4, 4);
132
133 adjData = newData;
134 }
135 else
136 {
137 adjData = throttleData;
138 }
139
140 // 0.125f converts from bits to bytes
141 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
142 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
143 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
144 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
145 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
146 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
147 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
148 // State is a subcategory of task that we allocate a percentage to
149
150
151 //int total = resend + land + wind + cloud + task + texture + asset;
152
153 byte[] data = new byte[7 * 4];
154 int ii = 0;
155
156 Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4;
157 Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4;
158 Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4;
159 Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4;
160 Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4;
161 Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4;
162 Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4);
163
164 try
165 {
166 presence.ControllingClient.SetChildAgentThrottle(data);
167 }
168 catch (NotImplementedException)
169 {
170 return;
171 }
172
173 }
174 } 92 }
175 93
176 private void RegionLoadedDoWork(Scene scene) 94 private void RegionLoadedDoWork(Scene scene)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index ee32755..61e4934 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -248,6 +248,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
248 248
249 } 249 }
250 250
251 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
252 {
253 // Remove a specific script
254
255 // Remove dataserver events
256 m_Dataserver[engine].RemoveEvents(localID, itemID);
257
258 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
259 if (comms != null)
260 comms.DeleteListener(itemID);
261
262 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
263 xmlrpc.DeleteChannels(itemID);
264 xmlrpc.CancelSRDRequests(itemID);
265
266 // Remove Sensors
267 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
268
269 }
270
251 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) 271 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
252 { 272 {
253 List<Object> data = new List<Object>(); 273 List<Object> data = new List<Object>();
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 30fb252..47492ea 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Diagnostics; //for [DebuggerNonUserCode]
31using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
32using System.Text; 33using System.Text;
33using System.Threading; 34using System.Threading;
@@ -81,7 +82,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
81 /// </summary> 82 /// </summary>
82 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi 83 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
83 { 84 {
84 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 85// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
85 protected IScriptEngine m_ScriptEngine; 86 protected IScriptEngine m_ScriptEngine;
86 protected SceneObjectPart m_host; 87 protected SceneObjectPart m_host;
87 protected uint m_localID; 88 protected uint m_localID;
@@ -99,6 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
99 protected int m_notecardLineReadCharsMax = 255; 100 protected int m_notecardLineReadCharsMax = 255;
100 protected int m_scriptConsoleChannel = 0; 101 protected int m_scriptConsoleChannel = 0;
101 protected bool m_scriptConsoleChannelEnabled = false; 102 protected bool m_scriptConsoleChannelEnabled = false;
103 protected bool m_debuggerSafe = false;
102 protected IUrlModule m_UrlModule = null; 104 protected IUrlModule m_UrlModule = null;
103 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = 105 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache =
104 new Dictionary<UUID, UserInfoCacheEntry>(); 106 new Dictionary<UUID, UserInfoCacheEntry>();
@@ -109,6 +111,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
109 m_host = host; 111 m_host = host;
110 m_localID = localID; 112 m_localID = localID;
111 m_itemID = itemID; 113 m_itemID = itemID;
114 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
112 115
113 m_ScriptDelayFactor = 116 m_ScriptDelayFactor =
114 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); 117 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
@@ -161,6 +164,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
161 get { return m_ScriptEngine.World; } 164 get { return m_ScriptEngine.World; }
162 } 165 }
163 166
167 [DebuggerNonUserCode]
164 public void state(string newState) 168 public void state(string newState)
165 { 169 {
166 m_ScriptEngine.SetState(m_itemID, newState); 170 m_ScriptEngine.SetState(m_itemID, newState);
@@ -170,6 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
170 /// Reset the named script. The script must be present 174 /// Reset the named script. The script must be present
171 /// in the same prim. 175 /// in the same prim.
172 /// </summary> 176 /// </summary>
177 [DebuggerNonUserCode]
173 public void llResetScript() 178 public void llResetScript()
174 { 179 {
175 m_host.AddScriptLPS(1); 180 m_host.AddScriptLPS(1);
@@ -226,9 +231,62 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
226 } 231 }
227 } 232 }
228 233
234 public List<ScenePresence> GetLinkAvatars(int linkType)
235 {
236 List<ScenePresence> ret = new List<ScenePresence>();
237 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
238 return ret;
239
240 List<ScenePresence> avs = m_host.ParentGroup.GetLinkedAvatars();
241
242 switch (linkType)
243 {
244 case ScriptBaseClass.LINK_SET:
245 return avs;
246
247 case ScriptBaseClass.LINK_ROOT:
248 return ret;
249
250 case ScriptBaseClass.LINK_ALL_OTHERS:
251 return avs;
252
253 case ScriptBaseClass.LINK_ALL_CHILDREN:
254 return avs;
255
256 case ScriptBaseClass.LINK_THIS:
257 return ret;
258
259 default:
260 if (linkType < 0)
261 return ret;
262
263 int partCount = m_host.ParentGroup.GetPartCount();
264
265 if (linkType <= partCount)
266 {
267 return ret;
268 }
269 else
270 {
271 linkType = linkType - partCount;
272 if (linkType > avs.Count)
273 {
274 return ret;
275 }
276 else
277 {
278 ret.Add(avs[linkType-1]);
279 return ret;
280 }
281 }
282 }
283 }
284
229 public List<SceneObjectPart> GetLinkParts(int linkType) 285 public List<SceneObjectPart> GetLinkParts(int linkType)
230 { 286 {
231 List<SceneObjectPart> ret = new List<SceneObjectPart>(); 287 List<SceneObjectPart> ret = new List<SceneObjectPart>();
288 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
289 return ret;
232 ret.Add(m_host); 290 ret.Add(m_host);
233 291
234 switch (linkType) 292 switch (linkType)
@@ -288,40 +346,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
288 protected UUID InventorySelf() 346 protected UUID InventorySelf()
289 { 347 {
290 UUID invItemID = new UUID(); 348 UUID invItemID = new UUID();
291 349 bool unlock = false;
292 lock (m_host.TaskInventory) 350 if (!m_host.TaskInventory.IsReadLockedByMe())
293 { 351 {
294 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 352 m_host.TaskInventory.LockItemsForRead(true);
353 unlock = true;
354 }
355 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
356 {
357 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
295 { 358 {
296 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) 359 invItemID = inv.Key;
297 { 360 break;
298 invItemID = inv.Key;
299 break;
300 }
301 } 361 }
302 } 362 }
303 363 if (unlock)
364 {
365 m_host.TaskInventory.LockItemsForRead(false);
366 }
304 return invItemID; 367 return invItemID;
305 } 368 }
306 369
307 protected UUID InventoryKey(string name, int type) 370 protected UUID InventoryKey(string name, int type)
308 { 371 {
309 m_host.AddScriptLPS(1); 372 m_host.AddScriptLPS(1);
310 373 m_host.TaskInventory.LockItemsForRead(true);
311 lock (m_host.TaskInventory) 374
375 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
312 { 376 {
313 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 377 if (inv.Value.Name == name)
314 { 378 {
315 if (inv.Value.Name == name) 379 m_host.TaskInventory.LockItemsForRead(false);
380
381 if (inv.Value.Type != type)
316 { 382 {
317 if (inv.Value.Type != type) 383 return UUID.Zero;
318 return UUID.Zero;
319
320 return inv.Value.AssetID;
321 } 384 }
385
386 return inv.Value.AssetID;
322 } 387 }
323 } 388 }
324 389
390 m_host.TaskInventory.LockItemsForRead(false);
325 return UUID.Zero; 391 return UUID.Zero;
326 } 392 }
327 393
@@ -329,17 +395,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
329 { 395 {
330 m_host.AddScriptLPS(1); 396 m_host.AddScriptLPS(1);
331 397
332 lock (m_host.TaskInventory) 398
399 m_host.TaskInventory.LockItemsForRead(true);
400
401 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
333 { 402 {
334 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 403 if (inv.Value.Name == name)
335 { 404 {
336 if (inv.Value.Name == name) 405 m_host.TaskInventory.LockItemsForRead(false);
337 { 406 return inv.Value.AssetID;
338 return inv.Value.AssetID;
339 }
340 } 407 }
341 } 408 }
342 409
410 m_host.TaskInventory.LockItemsForRead(false);
411
412
343 return UUID.Zero; 413 return UUID.Zero;
344 } 414 }
345 415
@@ -481,26 +551,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
481 551
482 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke 552 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
483 553
484 // Old implementation of llRot2Euler. Normalization not required as Atan2 function will 554 // Utility function for llRot2Euler
485 // only return values >= -PI (-180 degrees) and <= PI (180 degrees).
486 555
487 public LSL_Vector llRot2Euler(LSL_Rotation r) 556 // normalize an angle between -PI and PI (-180 to +180 degrees)
557 protected double NormalizeAngle(double angle)
558 {
559 if (angle > -Math.PI && angle < Math.PI)
560 return angle;
561
562 int numPis = (int)(Math.PI / angle);
563 double remainder = angle - Math.PI * numPis;
564 if (numPis % 2 == 1)
565 return Math.PI - angle;
566 return remainder;
567 }
568
569 public LSL_Vector llRot2Euler(LSL_Rotation q1)
488 { 570 {
489 m_host.AddScriptLPS(1); 571 m_host.AddScriptLPS(1);
490 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke 572 LSL_Vector eul = new LSL_Vector();
491 LSL_Rotation t = new LSL_Rotation(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s); 573
492 double m = (t.x + t.y + t.z + t.s); 574 double sqw = q1.s*q1.s;
493 if (m == 0) return new LSL_Vector(); 575 double sqx = q1.x*q1.x;
494 double n = 2 * (r.y * r.s + r.x * r.z); 576 double sqy = q1.z*q1.z;
495 double p = m * m - n * n; 577 double sqz = q1.y*q1.y;
496 if (p > 0) 578 double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
497 return new LSL_Vector(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s)), 579 double test = q1.x*q1.z + q1.y*q1.s;
498 Math.Atan2(n, Math.Sqrt(p)), 580 if (test > 0.4999*unit) { // singularity at north pole
499 Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))); 581 eul.z = 2 * Math.Atan2(q1.x,q1.s);
500 else if (n > 0) 582 eul.y = Math.PI/2;
501 return new LSL_Vector(0.0, Math.PI * 0.5, Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)); 583 eul.x = 0;
502 else 584 return eul;
503 return new LSL_Vector(0.0, -Math.PI * 0.5, Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)); 585 }
586 if (test < -0.4999*unit) { // singularity at south pole
587 eul.z = -2 * Math.Atan2(q1.x,q1.s);
588 eul.y = -Math.PI/2;
589 eul.x = 0;
590 return eul;
591 }
592 eul.z = Math.Atan2(2*q1.z*q1.s-2*q1.x*q1.y , sqx - sqy - sqz + sqw);
593 eul.y = Math.Asin(2*test/unit);
594 eul.x = Math.Atan2(2*q1.x*q1.s-2*q1.z*q1.y , -sqx + sqy - sqz + sqw);
595 return eul;
504 } 596 }
505 597
506 /* From wiki: 598 /* From wiki:
@@ -702,77 +794,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
702 { 794 {
703 //A and B should both be normalized 795 //A and B should both be normalized
704 m_host.AddScriptLPS(1); 796 m_host.AddScriptLPS(1);
705 LSL_Rotation rotBetween; 797 /* This method is more accurate than the SL one, and thus causes problems
706 // Check for zero vectors. If either is zero, return zero rotation. Otherwise, 798 for scripts that deal with the SL inaccuracy around 180-degrees -.- .._.
707 // continue calculation. 799
708 if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f)) 800 double dotProduct = LSL_Vector.Dot(a, b);
709 { 801 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
710 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 802 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
711 } 803 double angle = Math.Acos(dotProduct / magProduct);
712 else 804 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
713 { 805 double s = Math.Sin(angle / 2);
714 a = LSL_Vector.Norm(a); 806
715 b = LSL_Vector.Norm(b); 807 double x = axis.x * s;
716 double dotProduct = LSL_Vector.Dot(a, b); 808 double y = axis.y * s;
717 // There are two degenerate cases possible. These are for vectors 180 or 809 double z = axis.z * s;
718 // 0 degrees apart. These have to be detected and handled individually. 810 double w = Math.Cos(angle / 2);
719 // 811
720 // Check for vectors 180 degrees apart. 812 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
721 // A dot product of -1 would mean the angle between vectors is 180 degrees. 813 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
722 if (dotProduct < -0.9999999f) 814
723 { 815 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
724 // First assume X axis is orthogonal to the vectors. 816 */
725 LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f); 817
726 orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a)); 818 // This method mimics the 180 errors found in SL
727 // Check for near zero vector. A very small non-zero number here will create 819 // See www.euclideanspace.com... angleBetween
728 // a rotation in an undesired direction. 820 LSL_Vector vec_a = a;
729 if (LSL_Vector.Mag(orthoVector) > 0.0001) 821 LSL_Vector vec_b = b;
730 { 822
731 rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f); 823 // Eliminate zero length
732 } 824 LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a);
733 // If the magnitude of the vector was near zero, then assume the X axis is not 825 LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b);
734 // orthogonal and use the Z axis instead. 826 if (vec_a_mag < 0.00001 ||
735 else 827 vec_b_mag < 0.00001)
736 { 828 {
737 // Set 180 z rotation. 829 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
738 rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f); 830 }
739 } 831
740 } 832 // Normalize
741 // Check for parallel vectors. 833 vec_a = llVecNorm(vec_a);
742 // A dot product of 1 would mean the angle between vectors is 0 degrees. 834 vec_b = llVecNorm(vec_b);
743 else if (dotProduct > 0.9999999f) 835
744 { 836 // Calculate axis and rotation angle
745 // Set zero rotation. 837 LSL_Vector axis = vec_a % vec_b;
746 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 838 LSL_Float cos_theta = vec_a * vec_b;
747 } 839
748 else 840 // Check if parallel
749 { 841 if (cos_theta > 0.99999)
750 // All special checks have been performed so get the axis of rotation. 842 {
751 LSL_Vector crossProduct = LSL_Vector.Cross(a, b); 843 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
752 // Quarternion s value is the length of the unit vector + dot product. 844 }
753 double qs = 1.0 + dotProduct; 845
754 rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs); 846 // Check if anti-parallel
755 // Normalize the rotation. 847 else if (cos_theta < -0.99999)
756 double mag = LSL_Rotation.Mag(rotBetween); 848 {
757 // We shouldn't have to worry about a divide by zero here. The qs value will be 849 LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a);
758 // non-zero because we already know if we're here, then the dotProduct is not -1 so 850 if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0);
759 // qs will not be zero. Also, we've already handled the input vectors being zero so the 851 return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0);
760 // crossProduct vector should also not be zero. 852 }
761 rotBetween.x = rotBetween.x / mag; 853 else // other rotation
762 rotBetween.y = rotBetween.y / mag; 854 {
763 rotBetween.z = rotBetween.z / mag; 855 LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f;
764 rotBetween.s = rotBetween.s / mag; 856 axis = llVecNorm(axis);
765 // Check for undefined values and set zero rotation if any found. This code might not actually be required 857 double x, y, z, s, t;
766 // any longer since zero vectors are checked for at the top. 858 s = Math.Cos(theta);
767 if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s)) 859 t = Math.Sin(theta);
768 { 860 x = axis.x * t;
769 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 861 y = axis.y * t;
770 } 862 z = axis.z * t;
771 } 863 return new LSL_Rotation(x,y,z,s);
772 } 864 }
773 return rotBetween; 865 }
774 } 866
775
776 public void llWhisper(int channelID, string text) 867 public void llWhisper(int channelID, string text)
777 { 868 {
778 m_host.AddScriptLPS(1); 869 m_host.AddScriptLPS(1);
@@ -1096,10 +1187,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1096 return detectedParams.TouchUV; 1187 return detectedParams.TouchUV;
1097 } 1188 }
1098 1189
1190 [DebuggerNonUserCode]
1099 public virtual void llDie() 1191 public virtual void llDie()
1100 { 1192 {
1101 m_host.AddScriptLPS(1); 1193 m_host.AddScriptLPS(1);
1102 throw new SelfDeleteException(); 1194 if (!m_host.IsAttachment) throw new SelfDeleteException();
1103 } 1195 }
1104 1196
1105 public LSL_Float llGround(LSL_Vector offset) 1197 public LSL_Float llGround(LSL_Vector offset)
@@ -1172,6 +1264,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1172 1264
1173 public void llSetStatus(int status, int value) 1265 public void llSetStatus(int status, int value)
1174 { 1266 {
1267 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
1268 return;
1175 m_host.AddScriptLPS(1); 1269 m_host.AddScriptLPS(1);
1176 1270
1177 int statusrotationaxis = 0; 1271 int statusrotationaxis = 0;
@@ -1402,6 +1496,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1402 { 1496 {
1403 m_host.AddScriptLPS(1); 1497 m_host.AddScriptLPS(1);
1404 1498
1499 SetColor(m_host, color, face);
1500 }
1501
1502 protected void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1503 {
1504 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1505 return;
1506
1507 Primitive.TextureEntry tex = part.Shape.Textures;
1508 Color4 texcolor;
1509 if (face >= 0 && face < GetNumberOfSides(part))
1510 {
1511 texcolor = tex.CreateFace((uint)face).RGBA;
1512 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1513 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1514 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1515 tex.FaceTextures[face].RGBA = texcolor;
1516 part.UpdateTexture(tex);
1517 return;
1518 }
1519 else if (face == ScriptBaseClass.ALL_SIDES)
1520 {
1521 for (uint i = 0; i < GetNumberOfSides(part); i++)
1522 {
1523 if (tex.FaceTextures[i] != null)
1524 {
1525 texcolor = tex.FaceTextures[i].RGBA;
1526 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1527 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1528 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1529 tex.FaceTextures[i].RGBA = texcolor;
1530 }
1531 texcolor = tex.DefaultTexture.RGBA;
1532 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1533 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1534 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1535 tex.DefaultTexture.RGBA = texcolor;
1536 }
1537 part.UpdateTexture(tex);
1538 return;
1539 }
1540
1405 if (face == ScriptBaseClass.ALL_SIDES) 1541 if (face == ScriptBaseClass.ALL_SIDES)
1406 face = SceneObjectPart.ALL_SIDES; 1542 face = SceneObjectPart.ALL_SIDES;
1407 1543
@@ -1410,6 +1546,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1410 1546
1411 public void SetTexGen(SceneObjectPart part, int face,int style) 1547 public void SetTexGen(SceneObjectPart part, int face,int style)
1412 { 1548 {
1549 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1550 return;
1551
1413 Primitive.TextureEntry tex = part.Shape.Textures; 1552 Primitive.TextureEntry tex = part.Shape.Textures;
1414 MappingType textype; 1553 MappingType textype;
1415 textype = MappingType.Default; 1554 textype = MappingType.Default;
@@ -1440,6 +1579,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1440 1579
1441 public void SetGlow(SceneObjectPart part, int face, float glow) 1580 public void SetGlow(SceneObjectPart part, int face, float glow)
1442 { 1581 {
1582 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1583 return;
1584
1443 Primitive.TextureEntry tex = part.Shape.Textures; 1585 Primitive.TextureEntry tex = part.Shape.Textures;
1444 if (face >= 0 && face < GetNumberOfSides(part)) 1586 if (face >= 0 && face < GetNumberOfSides(part))
1445 { 1587 {
@@ -1465,6 +1607,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1465 1607
1466 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) 1608 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1467 { 1609 {
1610 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1611 return;
1468 1612
1469 Shininess sval = new Shininess(); 1613 Shininess sval = new Shininess();
1470 1614
@@ -1515,6 +1659,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1515 1659
1516 public void SetFullBright(SceneObjectPart part, int face, bool bright) 1660 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1517 { 1661 {
1662 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1663 return;
1664
1518 Primitive.TextureEntry tex = part.Shape.Textures; 1665 Primitive.TextureEntry tex = part.Shape.Textures;
1519 if (face >= 0 && face < GetNumberOfSides(part)) 1666 if (face >= 0 && face < GetNumberOfSides(part))
1520 { 1667 {
@@ -1575,13 +1722,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1575 m_host.AddScriptLPS(1); 1722 m_host.AddScriptLPS(1);
1576 1723
1577 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1724 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1578 1725 if (parts.Count > 0)
1579 foreach (SceneObjectPart part in parts) 1726 {
1580 SetAlpha(part, alpha, face); 1727 try
1728 {
1729 parts[0].ParentGroup.areUpdatesSuspended = true;
1730 foreach (SceneObjectPart part in parts)
1731 SetAlpha(part, alpha, face);
1732 }
1733 finally
1734 {
1735 parts[0].ParentGroup.areUpdatesSuspended = false;
1736 }
1737 }
1581 } 1738 }
1582 1739
1583 protected void SetAlpha(SceneObjectPart part, double alpha, int face) 1740 protected void SetAlpha(SceneObjectPart part, double alpha, int face)
1584 { 1741 {
1742 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1743 return;
1744
1585 Primitive.TextureEntry tex = part.Shape.Textures; 1745 Primitive.TextureEntry tex = part.Shape.Textures;
1586 Color4 texcolor; 1746 Color4 texcolor;
1587 if (face >= 0 && face < GetNumberOfSides(part)) 1747 if (face >= 0 && face < GetNumberOfSides(part))
@@ -1627,7 +1787,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1627 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, 1787 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1628 float wind, float tension, LSL_Vector Force) 1788 float wind, float tension, LSL_Vector Force)
1629 { 1789 {
1630 if (part == null) 1790 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1631 return; 1791 return;
1632 1792
1633 if (flexi) 1793 if (flexi)
@@ -1662,7 +1822,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1662 /// <param name="falloff"></param> 1822 /// <param name="falloff"></param>
1663 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) 1823 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1664 { 1824 {
1665 if (part == null) 1825 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1666 return; 1826 return;
1667 1827
1668 if (light) 1828 if (light)
@@ -1739,15 +1899,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1739 m_host.AddScriptLPS(1); 1899 m_host.AddScriptLPS(1);
1740 1900
1741 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1901 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1742 1902 if (parts.Count > 0)
1743 foreach (SceneObjectPart part in parts) 1903 {
1744 SetTexture(part, texture, face); 1904 try
1745 1905 {
1906 parts[0].ParentGroup.areUpdatesSuspended = true;
1907 foreach (SceneObjectPart part in parts)
1908 SetTexture(part, texture, face);
1909 }
1910 finally
1911 {
1912 parts[0].ParentGroup.areUpdatesSuspended = false;
1913 }
1914 }
1746 ScriptSleep(200); 1915 ScriptSleep(200);
1747 } 1916 }
1748 1917
1749 protected void SetTexture(SceneObjectPart part, string texture, int face) 1918 protected void SetTexture(SceneObjectPart part, string texture, int face)
1750 { 1919 {
1920 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1921 return;
1922
1751 UUID textureID=new UUID(); 1923 UUID textureID=new UUID();
1752 1924
1753 if (!UUID.TryParse(texture, out textureID)) 1925 if (!UUID.TryParse(texture, out textureID))
@@ -1793,6 +1965,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1793 1965
1794 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) 1966 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1795 { 1967 {
1968 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1969 return;
1970
1796 Primitive.TextureEntry tex = part.Shape.Textures; 1971 Primitive.TextureEntry tex = part.Shape.Textures;
1797 if (face >= 0 && face < GetNumberOfSides(part)) 1972 if (face >= 0 && face < GetNumberOfSides(part))
1798 { 1973 {
@@ -1829,6 +2004,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1829 2004
1830 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) 2005 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1831 { 2006 {
2007 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2008 return;
2009
1832 Primitive.TextureEntry tex = part.Shape.Textures; 2010 Primitive.TextureEntry tex = part.Shape.Textures;
1833 if (face >= 0 && face < GetNumberOfSides(part)) 2011 if (face >= 0 && face < GetNumberOfSides(part))
1834 { 2012 {
@@ -1865,6 +2043,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1865 2043
1866 protected void RotateTexture(SceneObjectPart part, double rotation, int face) 2044 protected void RotateTexture(SceneObjectPart part, double rotation, int face)
1867 { 2045 {
2046 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2047 return;
2048
1868 Primitive.TextureEntry tex = part.Shape.Textures; 2049 Primitive.TextureEntry tex = part.Shape.Textures;
1869 if (face >= 0 && face < GetNumberOfSides(part)) 2050 if (face >= 0 && face < GetNumberOfSides(part))
1870 { 2051 {
@@ -1935,6 +2116,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1935 2116
1936 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) 2117 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1937 { 2118 {
2119 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2120 return;
2121
1938 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) 2122 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1939 LSL_Vector currentPos = GetPartLocalPos(part); 2123 LSL_Vector currentPos = GetPartLocalPos(part);
1940 2124
@@ -1951,7 +2135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1951 } 2135 }
1952 else 2136 else
1953 { 2137 {
1954 LSL_Vector rel_vec = SetPosAdjust(currentPos, targetPos); 2138 LSL_Vector rel_vec = SetPosAdjust(new LSL_Vector(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z), targetPos);
1955 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z); 2139 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z);
1956 SceneObjectGroup parent = part.ParentGroup; 2140 SceneObjectGroup parent = part.ParentGroup;
1957 parent.HasGroupChanged = true; 2141 parent.HasGroupChanged = true;
@@ -2003,9 +2187,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2003 m_host.AddScriptLPS(1); 2187 m_host.AddScriptLPS(1);
2004 2188
2005 // try to let this work as in SL... 2189 // try to let this work as in SL...
2006 if (m_host.ParentID == 0) 2190 if (m_host.LinkNum < 2)
2007 { 2191 {
2008 // special case: If we are root, rotate complete SOG to new rotation 2192 // Special case: If we are root, rotate complete SOG to new
2193 // rotation.
2194 // We are root if the link number is 0 (single prim) or 1
2195 // (root prim). ParentID may be nonzero in attachments and
2196 // using it would cause attachments and HUDs to rotate
2197 // to the wrong positions.
2009 SetRot(m_host, Rot2Quaternion(rot)); 2198 SetRot(m_host, Rot2Quaternion(rot));
2010 } 2199 }
2011 else 2200 else
@@ -2034,6 +2223,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2034 2223
2035 protected void SetRot(SceneObjectPart part, Quaternion rot) 2224 protected void SetRot(SceneObjectPart part, Quaternion rot)
2036 { 2225 {
2226 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2227 return;
2228
2037 part.UpdateRotation(rot); 2229 part.UpdateRotation(rot);
2038 // Update rotation does not move the object in the physics scene if it's a linkset. 2230 // Update rotation does not move the object in the physics scene if it's a linkset.
2039 2231
@@ -2653,12 +2845,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2653 2845
2654 m_host.AddScriptLPS(1); 2846 m_host.AddScriptLPS(1);
2655 2847
2848 m_host.TaskInventory.LockItemsForRead(true);
2656 TaskInventoryItem item = m_host.TaskInventory[invItemID]; 2849 TaskInventoryItem item = m_host.TaskInventory[invItemID];
2657 2850 m_host.TaskInventory.LockItemsForRead(false);
2658 lock (m_host.TaskInventory)
2659 {
2660 item = m_host.TaskInventory[invItemID];
2661 }
2662 2851
2663 if (item.PermsGranter == UUID.Zero) 2852 if (item.PermsGranter == UUID.Zero)
2664 return 0; 2853 return 0;
@@ -2733,6 +2922,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2733 if (dist > m_ScriptDistanceFactor * 10.0f) 2922 if (dist > m_ScriptDistanceFactor * 10.0f)
2734 return; 2923 return;
2735 2924
2925 //Clone is thread-safe
2736 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 2926 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
2737 2927
2738 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) 2928 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory)
@@ -2795,6 +2985,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2795 2985
2796 public void llLookAt(LSL_Vector target, double strength, double damping) 2986 public void llLookAt(LSL_Vector target, double strength, double damping)
2797 { 2987 {
2988 /*
2798 m_host.AddScriptLPS(1); 2989 m_host.AddScriptLPS(1);
2799 // Determine where we are looking from 2990 // Determine where we are looking from
2800 LSL_Vector from = llGetPos(); 2991 LSL_Vector from = llGetPos();
@@ -2814,10 +3005,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2814 // the angles of rotation in radians into rotation value 3005 // the angles of rotation in radians into rotation value
2815 3006
2816 LSL_Types.Quaternion rot = llEuler2Rot(angle); 3007 LSL_Types.Quaternion rot = llEuler2Rot(angle);
2817 Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s); 3008
2818 m_host.startLookAt(rotation, (float)damping, (float)strength); 3009 // This would only work if your physics system contains an APID controller:
3010 // Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
3011 // m_host.startLookAt(rotation, (float)damping, (float)strength);
3012
2819 // Orient the object to the angle calculated 3013 // Orient the object to the angle calculated
2820 //llSetRot(rot); 3014 llSetRot(rot);
3015 */
3016
3017 //The above code, while nice, doesn't replicate the behaviour of SL and tends to "roll" the object.
3018 //There's probably a smarter way of doing this, my rotation math-fu is weak.
3019 // http://bugs.meta7.com/view.php?id=28
3020 // - Tom
3021
3022 /* And the following does not do the job either. It has to be performed inside the ODE glue-code. -.- .._.
3023 LSL_Rotation newrot = llGetRot() * llRotBetween(new LSL_Vector(1.0d, 0.0d, 0.0d) * llGetRot(), new LSL_Vector(0.0d, 0.0d, -1.0d));
3024 llSetRot(newrot * llRotBetween(new LSL_Vector(0.0d,0.0d,1.0d) * newrot, target - llGetPos()));
3025 */
3026 // Send the target vector to RotLookAt method inside a 'rotation', the .w -99.9 value indicates it is really a LookAt.
3027 Quaternion q = new Quaternion((float)target.x, (float)target.y, (float)target.z, -99.9f);
3028 m_host.RotLookAt(q, (float)strength, (float)damping);
3029
3030 }
3031
3032 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3033 {
3034 m_host.AddScriptLPS(1);
3035// NotImplemented("llRotLookAt");
3036 m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping);
3037
2821 } 3038 }
2822 3039
2823 public void llStopLookAt() 3040 public void llStopLookAt()
@@ -2866,13 +3083,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2866 { 3083 {
2867 TaskInventoryItem item; 3084 TaskInventoryItem item;
2868 3085
2869 lock (m_host.TaskInventory) 3086 m_host.TaskInventory.LockItemsForRead(true);
3087 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2870 { 3088 {
2871 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3089 m_host.TaskInventory.LockItemsForRead(false);
2872 return; 3090 return;
2873 else
2874 item = m_host.TaskInventory[InventorySelf()];
2875 } 3091 }
3092 else
3093 {
3094 item = m_host.TaskInventory[InventorySelf()];
3095 }
3096 m_host.TaskInventory.LockItemsForRead(false);
2876 3097
2877 if (item.PermsGranter != UUID.Zero) 3098 if (item.PermsGranter != UUID.Zero)
2878 { 3099 {
@@ -2894,13 +3115,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2894 { 3115 {
2895 TaskInventoryItem item; 3116 TaskInventoryItem item;
2896 3117
3118 m_host.TaskInventory.LockItemsForRead(true);
2897 lock (m_host.TaskInventory) 3119 lock (m_host.TaskInventory)
2898 { 3120 {
3121
2899 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3122 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3123 {
3124 m_host.TaskInventory.LockItemsForRead(false);
2900 return; 3125 return;
3126 }
2901 else 3127 else
3128 {
2902 item = m_host.TaskInventory[InventorySelf()]; 3129 item = m_host.TaskInventory[InventorySelf()];
3130 }
2903 } 3131 }
3132 m_host.TaskInventory.LockItemsForRead(false);
2904 3133
2905 m_host.AddScriptLPS(1); 3134 m_host.AddScriptLPS(1);
2906 3135
@@ -2932,19 +3161,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2932 { 3161 {
2933 m_host.AddScriptLPS(1); 3162 m_host.AddScriptLPS(1);
2934 3163
2935 if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
2936 return;
2937
2938 TaskInventoryItem item; 3164 TaskInventoryItem item;
2939 3165
2940 lock (m_host.TaskInventory) 3166 m_host.TaskInventory.LockItemsForRead(true);
3167
3168 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2941 { 3169 {
2942 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3170 m_host.TaskInventory.LockItemsForRead(false);
2943 return; 3171 return;
2944 else 3172 }
2945 item = m_host.TaskInventory[InventorySelf()]; 3173 else
3174 {
3175 item = m_host.TaskInventory[InventorySelf()];
2946 } 3176 }
2947 3177
3178 m_host.TaskInventory.LockItemsForRead(false);
3179
2948 if (item.PermsGranter != m_host.OwnerID) 3180 if (item.PermsGranter != m_host.OwnerID)
2949 return; 3181 return;
2950 3182
@@ -2954,10 +3186,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2954 3186
2955 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 3187 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
2956 3188
2957 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; 3189 grp.AttachToAgent(m_host.OwnerID, (uint)attachment, Vector3.Zero, false);
2958 if (attachmentsModule != null)
2959 attachmentsModule.AttachObject(presence.ControllingClient,
2960 grp, (uint)attachment, false);
2961 } 3190 }
2962 } 3191 }
2963 3192
@@ -2970,13 +3199,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2970 3199
2971 TaskInventoryItem item; 3200 TaskInventoryItem item;
2972 3201
2973 lock (m_host.TaskInventory) 3202 m_host.TaskInventory.LockItemsForRead(true);
3203
3204 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2974 { 3205 {
2975 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3206 m_host.TaskInventory.LockItemsForRead(false);
2976 return; 3207 return;
2977 else 3208 }
2978 item = m_host.TaskInventory[InventorySelf()]; 3209 else
3210 {
3211 item = m_host.TaskInventory[InventorySelf()];
2979 } 3212 }
3213 m_host.TaskInventory.LockItemsForRead(false);
3214
2980 3215
2981 if (item.PermsGranter != m_host.OwnerID) 3216 if (item.PermsGranter != m_host.OwnerID)
2982 return; 3217 return;
@@ -3023,6 +3258,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3023 3258
3024 public void llInstantMessage(string user, string message) 3259 public void llInstantMessage(string user, string message)
3025 { 3260 {
3261 UUID result;
3262 if (!UUID.TryParse(user, out result))
3263 {
3264 ShoutError("An invalid key was passed to llInstantMessage");
3265 ScriptSleep(2000);
3266 return;
3267 }
3268
3269
3026 m_host.AddScriptLPS(1); 3270 m_host.AddScriptLPS(1);
3027 3271
3028 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. 3272 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
@@ -3037,14 +3281,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3037 UUID friendTransactionID = UUID.Random(); 3281 UUID friendTransactionID = UUID.Random();
3038 3282
3039 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); 3283 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
3040 3284
3041 GridInstantMessage msg = new GridInstantMessage(); 3285 GridInstantMessage msg = new GridInstantMessage();
3042 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; 3286 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
3043 msg.toAgentID = new Guid(user); // toAgentID.Guid; 3287 msg.toAgentID = new Guid(user); // toAgentID.Guid;
3044 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here 3288 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
3045// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message); 3289// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
3046// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString()); 3290// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
3047 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp; 3291// DateTime dt = DateTime.UtcNow;
3292//
3293// // Ticks from UtcNow, but make it look like local. Evil, huh?
3294// dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
3295//
3296// try
3297// {
3298// // Convert that to the PST timezone
3299// TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
3300// dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
3301// }
3302// catch
3303// {
3304// // No logging here, as it could be VERY spammy
3305// }
3306//
3307// // And make it look local again to fool the unix time util
3308// dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
3309
3310 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
3311
3048 //if (client != null) 3312 //if (client != null)
3049 //{ 3313 //{
3050 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName; 3314 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
@@ -3058,13 +3322,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3058 msg.message = message.Substring(0, 1024); 3322 msg.message = message.Substring(0, 1024);
3059 else 3323 else
3060 msg.message = message; 3324 msg.message = message;
3061 msg.dialog = (byte)19; // messgage from script ??? // dialog; 3325 msg.dialog = (byte)19; // MessageFromObject
3062 msg.fromGroup = false;// fromGroup; 3326 msg.fromGroup = false;// fromGroup;
3063 msg.offline = (byte)0; //offline; 3327 msg.offline = (byte)0; //offline;
3064 msg.ParentEstateID = 0; //ParentEstateID; 3328 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID;
3065 msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition); 3329 msg.Position = new Vector3(m_host.AbsolutePosition);
3066 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; 3330 msg.RegionID = World.RegionInfo.RegionID.Guid;
3067 msg.binaryBucket = new byte[0];// binaryBucket; 3331 msg.binaryBucket = Util.StringToBytes256(m_host.OwnerID.ToString());
3068 3332
3069 if (m_TransferModule != null) 3333 if (m_TransferModule != null)
3070 { 3334 {
@@ -3084,7 +3348,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3084 } 3348 }
3085 3349
3086 emailModule.SendEmail(m_host.UUID, address, subject, message); 3350 emailModule.SendEmail(m_host.UUID, address, subject, message);
3087 ScriptSleep(20000); 3351 ScriptSleep(15000);
3088 } 3352 }
3089 3353
3090 public void llGetNextEmail(string address, string subject) 3354 public void llGetNextEmail(string address, string subject)
@@ -3186,13 +3450,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3186 m_host.AddScriptLPS(1); 3450 m_host.AddScriptLPS(1);
3187 } 3451 }
3188 3452
3189 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3190 {
3191 m_host.AddScriptLPS(1);
3192 Quaternion rot = new Quaternion((float)target.x, (float)target.y, (float)target.z, (float)target.s);
3193 m_host.RotLookAt(rot, (float)strength, (float)damping);
3194 }
3195
3196 public LSL_Integer llStringLength(string str) 3453 public LSL_Integer llStringLength(string str)
3197 { 3454 {
3198 m_host.AddScriptLPS(1); 3455 m_host.AddScriptLPS(1);
@@ -3216,14 +3473,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3216 3473
3217 TaskInventoryItem item; 3474 TaskInventoryItem item;
3218 3475
3219 lock (m_host.TaskInventory) 3476 m_host.TaskInventory.LockItemsForRead(true);
3477 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3220 { 3478 {
3221 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3479 m_host.TaskInventory.LockItemsForRead(false);
3222 return; 3480 return;
3223 else
3224 item = m_host.TaskInventory[InventorySelf()];
3225 } 3481 }
3226 3482 else
3483 {
3484 item = m_host.TaskInventory[InventorySelf()];
3485 }
3486 m_host.TaskInventory.LockItemsForRead(false);
3227 if (item.PermsGranter == UUID.Zero) 3487 if (item.PermsGranter == UUID.Zero)
3228 return; 3488 return;
3229 3489
@@ -3253,13 +3513,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3253 3513
3254 TaskInventoryItem item; 3514 TaskInventoryItem item;
3255 3515
3256 lock (m_host.TaskInventory) 3516 m_host.TaskInventory.LockItemsForRead(true);
3517 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3257 { 3518 {
3258 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3519 m_host.TaskInventory.LockItemsForRead(false);
3259 return; 3520 return;
3260 else
3261 item = m_host.TaskInventory[InventorySelf()];
3262 } 3521 }
3522 else
3523 {
3524 item = m_host.TaskInventory[InventorySelf()];
3525 }
3526 m_host.TaskInventory.LockItemsForRead(false);
3527
3263 3528
3264 if (item.PermsGranter == UUID.Zero) 3529 if (item.PermsGranter == UUID.Zero)
3265 return; 3530 return;
@@ -3330,10 +3595,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3330 3595
3331 TaskInventoryItem item; 3596 TaskInventoryItem item;
3332 3597
3333 lock (m_host.TaskInventory) 3598
3599 m_host.TaskInventory.LockItemsForRead(true);
3600 if (!m_host.TaskInventory.ContainsKey(invItemID))
3601 {
3602 m_host.TaskInventory.LockItemsForRead(false);
3603 return;
3604 }
3605 else
3334 { 3606 {
3335 item = m_host.TaskInventory[invItemID]; 3607 item = m_host.TaskInventory[invItemID];
3336 } 3608 }
3609 m_host.TaskInventory.LockItemsForRead(false);
3337 3610
3338 if (agentID == UUID.Zero || perm == 0) // Releasing permissions 3611 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3339 { 3612 {
@@ -3365,11 +3638,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3365 3638
3366 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3639 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3367 { 3640 {
3368 lock (m_host.TaskInventory) 3641 m_host.TaskInventory.LockItemsForWrite(true);
3369 { 3642 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3370 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3643 m_host.TaskInventory[invItemID].PermsMask = perm;
3371 m_host.TaskInventory[invItemID].PermsMask = perm; 3644 m_host.TaskInventory.LockItemsForWrite(false);
3372 }
3373 3645
3374 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3646 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3375 "run_time_permissions", new Object[] { 3647 "run_time_permissions", new Object[] {
@@ -3389,11 +3661,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3389 3661
3390 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3662 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3391 { 3663 {
3392 lock (m_host.TaskInventory) 3664 m_host.TaskInventory.LockItemsForWrite(true);
3393 { 3665 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3394 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3666 m_host.TaskInventory[invItemID].PermsMask = perm;
3395 m_host.TaskInventory[invItemID].PermsMask = perm; 3667 m_host.TaskInventory.LockItemsForWrite(false);
3396 }
3397 3668
3398 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3669 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3399 "run_time_permissions", new Object[] { 3670 "run_time_permissions", new Object[] {
@@ -3414,11 +3685,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3414 3685
3415 if (!m_waitingForScriptAnswer) 3686 if (!m_waitingForScriptAnswer)
3416 { 3687 {
3417 lock (m_host.TaskInventory) 3688 m_host.TaskInventory.LockItemsForWrite(true);
3418 { 3689 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3419 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3690 m_host.TaskInventory[invItemID].PermsMask = 0;
3420 m_host.TaskInventory[invItemID].PermsMask = 0; 3691 m_host.TaskInventory.LockItemsForWrite(false);
3421 }
3422 3692
3423 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; 3693 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3424 m_waitingForScriptAnswer=true; 3694 m_waitingForScriptAnswer=true;
@@ -3453,10 +3723,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3453 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) 3723 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3454 llReleaseControls(); 3724 llReleaseControls();
3455 3725
3456 lock (m_host.TaskInventory) 3726
3457 { 3727 m_host.TaskInventory.LockItemsForWrite(true);
3458 m_host.TaskInventory[invItemID].PermsMask = answer; 3728 m_host.TaskInventory[invItemID].PermsMask = answer;
3459 } 3729 m_host.TaskInventory.LockItemsForWrite(false);
3730
3460 3731
3461 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3732 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3462 "run_time_permissions", new Object[] { 3733 "run_time_permissions", new Object[] {
@@ -3468,16 +3739,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3468 { 3739 {
3469 m_host.AddScriptLPS(1); 3740 m_host.AddScriptLPS(1);
3470 3741
3471 lock (m_host.TaskInventory) 3742 m_host.TaskInventory.LockItemsForRead(true);
3743
3744 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3472 { 3745 {
3473 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3746 if (item.Type == 10 && item.ItemID == m_itemID)
3474 { 3747 {
3475 if (item.Type == 10 && item.ItemID == m_itemID) 3748 m_host.TaskInventory.LockItemsForRead(false);
3476 { 3749 return item.PermsGranter.ToString();
3477 return item.PermsGranter.ToString();
3478 }
3479 } 3750 }
3480 } 3751 }
3752 m_host.TaskInventory.LockItemsForRead(false);
3481 3753
3482 return UUID.Zero.ToString(); 3754 return UUID.Zero.ToString();
3483 } 3755 }
@@ -3486,19 +3758,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3486 { 3758 {
3487 m_host.AddScriptLPS(1); 3759 m_host.AddScriptLPS(1);
3488 3760
3489 lock (m_host.TaskInventory) 3761 m_host.TaskInventory.LockItemsForRead(true);
3762
3763 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3490 { 3764 {
3491 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3765 if (item.Type == 10 && item.ItemID == m_itemID)
3492 { 3766 {
3493 if (item.Type == 10 && item.ItemID == m_itemID) 3767 int perms = item.PermsMask;
3494 { 3768 if (m_automaticLinkPermission)
3495 int perms = item.PermsMask; 3769 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3496 if (m_automaticLinkPermission) 3770 m_host.TaskInventory.LockItemsForRead(false);
3497 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 3771 return perms;
3498 return perms;
3499 }
3500 } 3772 }
3501 } 3773 }
3774 m_host.TaskInventory.LockItemsForRead(false);
3502 3775
3503 return 0; 3776 return 0;
3504 } 3777 }
@@ -3520,9 +3793,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3520 public void llSetLinkColor(int linknumber, LSL_Vector color, int face) 3793 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3521 { 3794 {
3522 List<SceneObjectPart> parts = GetLinkParts(linknumber); 3795 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3523 3796 if (parts.Count > 0)
3524 foreach (SceneObjectPart part in parts) 3797 {
3525 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 3798 try
3799 {
3800 parts[0].ParentGroup.areUpdatesSuspended = true;
3801 foreach (SceneObjectPart part in parts)
3802 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face);
3803 }
3804 finally
3805 {
3806 parts[0].ParentGroup.areUpdatesSuspended = false;
3807 }
3808 }
3526 } 3809 }
3527 3810
3528 public void llCreateLink(string target, int parent) 3811 public void llCreateLink(string target, int parent)
@@ -3535,11 +3818,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3535 return; 3818 return;
3536 3819
3537 TaskInventoryItem item; 3820 TaskInventoryItem item;
3538 lock (m_host.TaskInventory) 3821 m_host.TaskInventory.LockItemsForRead(true);
3539 { 3822 item = m_host.TaskInventory[invItemID];
3540 item = m_host.TaskInventory[invItemID]; 3823 m_host.TaskInventory.LockItemsForRead(false);
3541 } 3824
3542
3543 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3825 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3544 && !m_automaticLinkPermission) 3826 && !m_automaticLinkPermission)
3545 { 3827 {
@@ -3560,7 +3842,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3560 3842
3561 if (targetPart != null) 3843 if (targetPart != null)
3562 { 3844 {
3563 if (parent != 0) { 3845 if (parent != 0)
3846 {
3564 parentPrim = m_host.ParentGroup; 3847 parentPrim = m_host.ParentGroup;
3565 childPrim = targetPart.ParentGroup; 3848 childPrim = targetPart.ParentGroup;
3566 } 3849 }
@@ -3592,16 +3875,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3592 m_host.AddScriptLPS(1); 3875 m_host.AddScriptLPS(1);
3593 UUID invItemID = InventorySelf(); 3876 UUID invItemID = InventorySelf();
3594 3877
3595 lock (m_host.TaskInventory) 3878 m_host.TaskInventory.LockItemsForRead(true);
3596 {
3597 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3879 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3598 && !m_automaticLinkPermission) 3880 && !m_automaticLinkPermission)
3599 { 3881 {
3600 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); 3882 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
3883 m_host.TaskInventory.LockItemsForRead(false);
3601 return; 3884 return;
3602 } 3885 }
3603 } 3886 m_host.TaskInventory.LockItemsForRead(false);
3604 3887
3605 if (linknum < ScriptBaseClass.LINK_THIS) 3888 if (linknum < ScriptBaseClass.LINK_THIS)
3606 return; 3889 return;
3607 3890
@@ -3640,10 +3923,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3640 // Restructuring Multiple Prims. 3923 // Restructuring Multiple Prims.
3641 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); 3924 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3642 parts.Remove(parentPrim.RootPart); 3925 parts.Remove(parentPrim.RootPart);
3643 foreach (SceneObjectPart part in parts) 3926 if (parts.Count > 0)
3644 { 3927 {
3645 parentPrim.DelinkFromGroup(part.LocalId, true); 3928 try
3929 {
3930 parts[0].ParentGroup.areUpdatesSuspended = true;
3931 foreach (SceneObjectPart part in parts)
3932 {
3933 parentPrim.DelinkFromGroup(part.LocalId, true);
3934 }
3935 }
3936 finally
3937 {
3938 parts[0].ParentGroup.areUpdatesSuspended = false;
3939 }
3646 } 3940 }
3941
3647 parentPrim.HasGroupChanged = true; 3942 parentPrim.HasGroupChanged = true;
3648 parentPrim.ScheduleGroupForFullUpdate(); 3943 parentPrim.ScheduleGroupForFullUpdate();
3649 parentPrim.TriggerScriptChangedEvent(Changed.LINK); 3944 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
@@ -3652,11 +3947,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3652 { 3947 {
3653 SceneObjectPart newRoot = parts[0]; 3948 SceneObjectPart newRoot = parts[0];
3654 parts.Remove(newRoot); 3949 parts.Remove(newRoot);
3655 foreach (SceneObjectPart part in parts) 3950
3951 try
3656 { 3952 {
3657 part.UpdateFlag = 0; 3953 parts[0].ParentGroup.areUpdatesSuspended = true;
3658 newRoot.ParentGroup.LinkToGroup(part.ParentGroup); 3954 foreach (SceneObjectPart part in parts)
3955 {
3956 part.UpdateFlag = 0;
3957 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3958 }
3659 } 3959 }
3960 finally
3961 {
3962 parts[0].ParentGroup.areUpdatesSuspended = false;
3963 }
3964
3965
3660 newRoot.ParentGroup.HasGroupChanged = true; 3966 newRoot.ParentGroup.HasGroupChanged = true;
3661 newRoot.ParentGroup.ScheduleGroupForFullUpdate(); 3967 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3662 } 3968 }
@@ -3702,6 +4008,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3702 } 4008 }
3703 else 4009 else
3704 { 4010 {
4011 if (linknum > m_host.ParentGroup.PrimCount || (linknum == 1 && m_host.ParentGroup.PrimCount == 1))
4012 {
4013 linknum -= (m_host.ParentGroup.PrimCount) + 1;
4014
4015 if (linknum < 0)
4016 return UUID.Zero.ToString();
4017
4018 List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET);
4019 if (avatars.Count > linknum)
4020 {
4021 return avatars[linknum].UUID.ToString();
4022 }
4023 }
3705 return UUID.Zero.ToString(); 4024 return UUID.Zero.ToString();
3706 } 4025 }
3707 } 4026 }
@@ -3778,17 +4097,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3778 m_host.AddScriptLPS(1); 4097 m_host.AddScriptLPS(1);
3779 int count = 0; 4098 int count = 0;
3780 4099
3781 lock (m_host.TaskInventory) 4100 m_host.TaskInventory.LockItemsForRead(true);
4101 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3782 { 4102 {
3783 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4103 if (inv.Value.Type == type || type == -1)
3784 { 4104 {
3785 if (inv.Value.Type == type || type == -1) 4105 count = count + 1;
3786 {
3787 count = count + 1;
3788 }
3789 } 4106 }
3790 } 4107 }
3791 4108
4109 m_host.TaskInventory.LockItemsForRead(false);
3792 return count; 4110 return count;
3793 } 4111 }
3794 4112
@@ -3797,16 +4115,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3797 m_host.AddScriptLPS(1); 4115 m_host.AddScriptLPS(1);
3798 ArrayList keys = new ArrayList(); 4116 ArrayList keys = new ArrayList();
3799 4117
3800 lock (m_host.TaskInventory) 4118 m_host.TaskInventory.LockItemsForRead(true);
4119 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3801 { 4120 {
3802 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4121 if (inv.Value.Type == type || type == -1)
3803 { 4122 {
3804 if (inv.Value.Type == type || type == -1) 4123 keys.Add(inv.Value.Name);
3805 {
3806 keys.Add(inv.Value.Name);
3807 }
3808 } 4124 }
3809 } 4125 }
4126 m_host.TaskInventory.LockItemsForRead(false);
3810 4127
3811 if (keys.Count == 0) 4128 if (keys.Count == 0)
3812 { 4129 {
@@ -3843,20 +4160,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3843 } 4160 }
3844 4161
3845 // move the first object found with this inventory name 4162 // move the first object found with this inventory name
3846 lock (m_host.TaskInventory) 4163 m_host.TaskInventory.LockItemsForRead(true);
4164 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3847 { 4165 {
3848 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4166 if (inv.Value.Name == inventory)
3849 { 4167 {
3850 if (inv.Value.Name == inventory) 4168 found = true;
3851 { 4169 objId = inv.Key;
3852 found = true; 4170 assetType = inv.Value.Type;
3853 objId = inv.Key; 4171 objName = inv.Value.Name;
3854 assetType = inv.Value.Type; 4172 break;
3855 objName = inv.Value.Name;
3856 break;
3857 }
3858 } 4173 }
3859 } 4174 }
4175 m_host.TaskInventory.LockItemsForRead(false);
3860 4176
3861 if (!found) 4177 if (!found)
3862 { 4178 {
@@ -3864,9 +4180,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3864 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); 4180 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3865 } 4181 }
3866 4182
3867 // check if destination is an avatar 4183 // check if destination is an object
3868 if (World.GetScenePresence(destId) != null) 4184 if (World.GetSceneObjectPart(destId) != null)
3869 { 4185 {
4186 // destination is an object
4187 World.MoveTaskInventoryItem(destId, m_host, objId);
4188 }
4189 else
4190 {
4191 ScenePresence presence = World.GetScenePresence(destId);
4192
4193 if (presence == null)
4194 {
4195 UserAccount account =
4196 World.UserAccountService.GetUserAccount(
4197 World.RegionInfo.ScopeID,
4198 destId);
4199
4200 if (account == null)
4201 {
4202 llSay(0, "Can't find destination "+destId.ToString());
4203 return;
4204 }
4205 }
4206
3870 // destination is an avatar 4207 // destination is an avatar
3871 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); 4208 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
3872 4209
@@ -3890,31 +4227,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3890 4227
3891 if (m_TransferModule != null) 4228 if (m_TransferModule != null)
3892 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 4229 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4230
4231 //This delay should only occur when giving inventory to avatars.
4232 ScriptSleep(3000);
3893 } 4233 }
3894 else
3895 {
3896 // destination is an object
3897 World.MoveTaskInventoryItem(destId, m_host, objId);
3898 }
3899 ScriptSleep(3000);
3900 } 4234 }
3901 4235
4236 [DebuggerNonUserCode]
3902 public void llRemoveInventory(string name) 4237 public void llRemoveInventory(string name)
3903 { 4238 {
3904 m_host.AddScriptLPS(1); 4239 m_host.AddScriptLPS(1);
3905 4240
3906 lock (m_host.TaskInventory) 4241 List<TaskInventoryItem> inv;
4242 try
3907 { 4243 {
3908 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4244 m_host.TaskInventory.LockItemsForRead(true);
4245 inv = new List<TaskInventoryItem>(m_host.TaskInventory.Values);
4246 }
4247 finally
4248 {
4249 m_host.TaskInventory.LockItemsForRead(false);
4250 }
4251 foreach (TaskInventoryItem item in inv)
4252 {
4253 if (item.Name == name)
3909 { 4254 {
3910 if (item.Name == name) 4255 if (item.ItemID == m_itemID)
3911 { 4256 throw new ScriptDeleteException();
3912 if (item.ItemID == m_itemID) 4257 else
3913 throw new ScriptDeleteException(); 4258 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3914 else 4259 return;
3915 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3916 return;
3917 }
3918 } 4260 }
3919 } 4261 }
3920 } 4262 }
@@ -3980,6 +4322,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3980 ce.time = Util.EnvironmentTickCount(); 4322 ce.time = Util.EnvironmentTickCount();
3981 ce.account = account; 4323 ce.account = account;
3982 ce.pinfo = pinfo; 4324 ce.pinfo = pinfo;
4325 m_userInfoCache[uuid] = ce;
3983 } 4326 }
3984 else 4327 else
3985 { 4328 {
@@ -4055,6 +4398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4055 { 4398 {
4056 m_host.AddScriptLPS(1); 4399 m_host.AddScriptLPS(1);
4057 4400
4401 //Clone is thread safe
4058 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 4402 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
4059 4403
4060 foreach (TaskInventoryItem item in itemDictionary.Values) 4404 foreach (TaskInventoryItem item in itemDictionary.Values)
@@ -4108,6 +4452,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4108 ScenePresence presence = World.GetScenePresence(agentId); 4452 ScenePresence presence = World.GetScenePresence(agentId);
4109 if (presence != null) 4453 if (presence != null)
4110 { 4454 {
4455 // agent must not be a god
4456 if (presence.GodLevel >= 200) return;
4457
4111 // agent must be over the owners land 4458 // agent must be over the owners land
4112 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4459 if (m_host.OwnerID == World.LandChannel.GetLandObject(
4113 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) 4460 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
@@ -4130,7 +4477,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4130 UUID av = new UUID(); 4477 UUID av = new UUID();
4131 if (!UUID.TryParse(agent,out av)) 4478 if (!UUID.TryParse(agent,out av))
4132 { 4479 {
4133 LSLError("First parameter to llDialog needs to be a key"); 4480 //LSLError("First parameter to llDialog needs to be a key");
4134 return; 4481 return;
4135 } 4482 }
4136 4483
@@ -4167,17 +4514,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4167 UUID soundId = UUID.Zero; 4514 UUID soundId = UUID.Zero;
4168 if (!UUID.TryParse(impact_sound, out soundId)) 4515 if (!UUID.TryParse(impact_sound, out soundId))
4169 { 4516 {
4170 lock (m_host.TaskInventory) 4517 m_host.TaskInventory.LockItemsForRead(true);
4518 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4171 { 4519 {
4172 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4520 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound)
4173 { 4521 {
4174 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) 4522 soundId = item.AssetID;
4175 { 4523 break;
4176 soundId = item.AssetID;
4177 break;
4178 }
4179 } 4524 }
4180 } 4525 }
4526 m_host.TaskInventory.LockItemsForRead(false);
4181 } 4527 }
4182 m_host.CollisionSound = soundId; 4528 m_host.CollisionSound = soundId;
4183 m_host.CollisionSoundVolume = (float)impact_volume; 4529 m_host.CollisionSoundVolume = (float)impact_volume;
@@ -4223,6 +4569,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4223 UUID partItemID; 4569 UUID partItemID;
4224 foreach (SceneObjectPart part in parts) 4570 foreach (SceneObjectPart part in parts)
4225 { 4571 {
4572 //Clone is thread safe
4226 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 4573 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
4227 4574
4228 foreach (TaskInventoryItem item in itemsDictionary.Values) 4575 foreach (TaskInventoryItem item in itemsDictionary.Values)
@@ -4437,17 +4784,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4437 4784
4438 m_host.AddScriptLPS(1); 4785 m_host.AddScriptLPS(1);
4439 4786
4440 lock (m_host.TaskInventory) 4787 m_host.TaskInventory.LockItemsForRead(true);
4788 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4441 { 4789 {
4442 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4790 if (item.Type == 10 && item.ItemID == m_itemID)
4443 { 4791 {
4444 if (item.Type == 10 && item.ItemID == m_itemID) 4792 result = item.Name!=null?item.Name:String.Empty;
4445 { 4793 break;
4446 result = item.Name != null ? item.Name : String.Empty;
4447 break;
4448 }
4449 } 4794 }
4450 } 4795 }
4796 m_host.TaskInventory.LockItemsForRead(false);
4451 4797
4452 return result; 4798 return result;
4453 } 4799 }
@@ -4600,23 +4946,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4600 { 4946 {
4601 m_host.AddScriptLPS(1); 4947 m_host.AddScriptLPS(1);
4602 4948
4603 lock (m_host.TaskInventory) 4949 m_host.TaskInventory.LockItemsForRead(true);
4950 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4604 { 4951 {
4605 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4952 if (inv.Value.Name == name)
4606 { 4953 {
4607 if (inv.Value.Name == name) 4954 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4608 { 4955 {
4609 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) 4956 m_host.TaskInventory.LockItemsForRead(false);
4610 { 4957 return inv.Value.AssetID.ToString();
4611 return inv.Value.AssetID.ToString(); 4958 }
4612 } 4959 else
4613 else 4960 {
4614 { 4961 m_host.TaskInventory.LockItemsForRead(false);
4615 return UUID.Zero.ToString(); 4962 return UUID.Zero.ToString();
4616 }
4617 } 4963 }
4618 } 4964 }
4619 } 4965 }
4966 m_host.TaskInventory.LockItemsForRead(false);
4620 4967
4621 return UUID.Zero.ToString(); 4968 return UUID.Zero.ToString();
4622 } 4969 }
@@ -4769,14 +5116,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4769 { 5116 {
4770 m_host.AddScriptLPS(1); 5117 m_host.AddScriptLPS(1);
4771 5118
4772 if (src == null) 5119 return src.Length;
4773 {
4774 return 0;
4775 }
4776 else
4777 {
4778 return src.Length;
4779 }
4780 } 5120 }
4781 5121
4782 public LSL_Integer llList2Integer(LSL_List src, int index) 5122 public LSL_Integer llList2Integer(LSL_List src, int index)
@@ -4822,7 +5162,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4822 else if (src.Data[index] is LSL_Float) 5162 else if (src.Data[index] is LSL_Float)
4823 return Convert.ToDouble(((LSL_Float) src.Data[index]).value); 5163 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
4824 else if (src.Data[index] is LSL_String) 5164 else if (src.Data[index] is LSL_String)
4825 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string); 5165 {
5166 string str = ((LSL_String) src.Data[index]).m_string;
5167 Match m = Regex.Match(str, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)");
5168 if (m != Match.Empty)
5169 {
5170 str = m.Value;
5171 double d = 0.0;
5172 if (!Double.TryParse(str, out d))
5173 return 0.0;
5174
5175 return d;
5176 }
5177 return 0.0;
5178 }
4826 return Convert.ToDouble(src.Data[index]); 5179 return Convert.ToDouble(src.Data[index]);
4827 } 5180 }
4828 catch (FormatException) 5181 catch (FormatException)
@@ -5095,7 +5448,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5095 } 5448 }
5096 } 5449 }
5097 } 5450 }
5098 else { 5451 else
5452 {
5099 object[] array = new object[src.Length]; 5453 object[] array = new object[src.Length];
5100 Array.Copy(src.Data, 0, array, 0, src.Length); 5454 Array.Copy(src.Data, 0, array, 0, src.Length);
5101 result = new LSL_List(array); 5455 result = new LSL_List(array);
@@ -5507,7 +5861,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5507 public void llSetSoundQueueing(int queue) 5861 public void llSetSoundQueueing(int queue)
5508 { 5862 {
5509 m_host.AddScriptLPS(1); 5863 m_host.AddScriptLPS(1);
5510 NotImplemented("llSetSoundQueueing");
5511 } 5864 }
5512 5865
5513 public void llSetSoundRadius(double radius) 5866 public void llSetSoundRadius(double radius)
@@ -5552,10 +5905,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5552 m_host.AddScriptLPS(1); 5905 m_host.AddScriptLPS(1);
5553 5906
5554 List<SceneObjectPart> parts = GetLinkParts(linknumber); 5907 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5555 5908 if (parts.Count > 0)
5556 foreach (var part in parts)
5557 { 5909 {
5558 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); 5910 try
5911 {
5912 parts[0].ParentGroup.areUpdatesSuspended = true;
5913 foreach (var part in parts)
5914 {
5915 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
5916 }
5917 }
5918 finally
5919 {
5920 parts[0].ParentGroup.areUpdatesSuspended = false;
5921 }
5559 } 5922 }
5560 } 5923 }
5561 5924
@@ -5609,6 +5972,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5609 ScriptSleep(5000); 5972 ScriptSleep(5000);
5610 } 5973 }
5611 5974
5975 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers)
5976 {
5977 return ParseString2List(str, separators, in_spacers, false);
5978 }
5979
5612 public LSL_Integer llOverMyLand(string id) 5980 public LSL_Integer llOverMyLand(string id)
5613 { 5981 {
5614 m_host.AddScriptLPS(1); 5982 m_host.AddScriptLPS(1);
@@ -5809,7 +6177,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5809 return m_host.ParentGroup.RootPart.AttachmentPoint; 6177 return m_host.ParentGroup.RootPart.AttachmentPoint;
5810 } 6178 }
5811 6179
5812 public LSL_Integer llGetFreeMemory() 6180 public virtual LSL_Integer llGetFreeMemory()
5813 { 6181 {
5814 m_host.AddScriptLPS(1); 6182 m_host.AddScriptLPS(1);
5815 // Make scripts designed for LSO happy 6183 // Make scripts designed for LSO happy
@@ -5926,7 +6294,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5926 SetParticleSystem(m_host, rules); 6294 SetParticleSystem(m_host, rules);
5927 } 6295 }
5928 6296
5929 private void SetParticleSystem(SceneObjectPart part, LSL_List rules) { 6297 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6298 {
5930 6299
5931 6300
5932 if (rules.Length == 0) 6301 if (rules.Length == 0)
@@ -6120,14 +6489,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6120 6489
6121 protected UUID GetTaskInventoryItem(string name) 6490 protected UUID GetTaskInventoryItem(string name)
6122 { 6491 {
6123 lock (m_host.TaskInventory) 6492 m_host.TaskInventory.LockItemsForRead(true);
6493 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6124 { 6494 {
6125 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6495 if (inv.Value.Name == name)
6126 { 6496 {
6127 if (inv.Value.Name == name) 6497 m_host.TaskInventory.LockItemsForRead(false);
6128 return inv.Key; 6498 return inv.Key;
6129 } 6499 }
6130 } 6500 }
6501 m_host.TaskInventory.LockItemsForRead(false);
6131 6502
6132 return UUID.Zero; 6503 return UUID.Zero;
6133 } 6504 }
@@ -6377,13 +6748,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6377 UUID av = new UUID(); 6748 UUID av = new UUID();
6378 if (!UUID.TryParse(avatar,out av)) 6749 if (!UUID.TryParse(avatar,out av))
6379 { 6750 {
6380 LSLError("First parameter to llDialog needs to be a key"); 6751 //LSLError("First parameter to llDialog needs to be a key");
6381 return; 6752 return;
6382 } 6753 }
6383 if (buttons.Length < 1) 6754 if (buttons.Length < 1)
6384 { 6755 {
6385 LSLError("No less than 1 button can be shown"); 6756 buttons.Add("OK");
6386 return;
6387 } 6757 }
6388 if (buttons.Length > 12) 6758 if (buttons.Length > 12)
6389 { 6759 {
@@ -6400,7 +6770,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6400 } 6770 }
6401 if (buttons.Data[i].ToString().Length > 24) 6771 if (buttons.Data[i].ToString().Length > 24)
6402 { 6772 {
6403 LSLError("button label cannot be longer than 24 characters"); 6773 llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters");
6404 return; 6774 return;
6405 } 6775 }
6406 buts[i] = buttons.Data[i].ToString(); 6776 buts[i] = buttons.Data[i].ToString();
@@ -6464,22 +6834,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6464 } 6834 }
6465 6835
6466 // copy the first script found with this inventory name 6836 // copy the first script found with this inventory name
6467 lock (m_host.TaskInventory) 6837 m_host.TaskInventory.LockItemsForRead(true);
6838 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6468 { 6839 {
6469 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6840 if (inv.Value.Name == name)
6470 { 6841 {
6471 if (inv.Value.Name == name) 6842 // make sure the object is a script
6843 if (10 == inv.Value.Type)
6472 { 6844 {
6473 // make sure the object is a script 6845 found = true;
6474 if (10 == inv.Value.Type) 6846 srcId = inv.Key;
6475 { 6847 break;
6476 found = true;
6477 srcId = inv.Key;
6478 break;
6479 }
6480 } 6848 }
6481 } 6849 }
6482 } 6850 }
6851 m_host.TaskInventory.LockItemsForRead(false);
6483 6852
6484 if (!found) 6853 if (!found)
6485 { 6854 {
@@ -6563,6 +6932,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6563 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) 6932 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
6564 { 6933 {
6565 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 6934 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6935 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
6936 return shapeBlock;
6566 6937
6567 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && 6938 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
6568 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && 6939 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
@@ -6638,6 +7009,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6638 7009
6639 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) 7010 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
6640 { 7011 {
7012 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7013 return;
7014
6641 ObjectShapePacket.ObjectDataBlock shapeBlock; 7015 ObjectShapePacket.ObjectDataBlock shapeBlock;
6642 7016
6643 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7017 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6687,6 +7061,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6687 7061
6688 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) 7062 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
6689 { 7063 {
7064 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7065 return;
7066
6690 ObjectShapePacket.ObjectDataBlock shapeBlock; 7067 ObjectShapePacket.ObjectDataBlock shapeBlock;
6691 7068
6692 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7069 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6729,6 +7106,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6729 7106
6730 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge) 7107 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge)
6731 { 7108 {
7109 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7110 return;
7111
6732 ObjectShapePacket.ObjectDataBlock shapeBlock; 7112 ObjectShapePacket.ObjectDataBlock shapeBlock;
6733 7113
6734 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7114 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6855,6 +7235,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6855 7235
6856 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) 7236 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
6857 { 7237 {
7238 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7239 return;
7240
6858 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 7241 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6859 UUID sculptId; 7242 UUID sculptId;
6860 7243
@@ -6870,13 +7253,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6870 shapeBlock.PathScaleX = 100; 7253 shapeBlock.PathScaleX = 100;
6871 shapeBlock.PathScaleY = 150; 7254 shapeBlock.PathScaleY = 150;
6872 7255
6873 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER && 7256 if ((type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER) == 0 &&
6874 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE && 7257 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE) == 0 &&
6875 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE && 7258 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE) == 0 &&
6876 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) 7259 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) == 0)
6877 { 7260 {
6878 // default 7261 // default
6879 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; 7262 type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
6880 } 7263 }
6881 7264
6882 // retain pathcurve 7265 // retain pathcurve
@@ -6895,30 +7278,82 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6895 ScriptSleep(200); 7278 ScriptSleep(200);
6896 } 7279 }
6897 7280
6898 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) 7281 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
6899 { 7282 {
6900 m_host.AddScriptLPS(1); 7283 m_host.AddScriptLPS(1);
6901 7284
6902 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7285 List<SceneObjectPart> parts = GetLinkParts(linknumber);
7286 List<ScenePresence> avatars = GetLinkAvatars(linknumber);
7287 if (parts.Count>0)
7288 {
7289 try
7290 {
7291 parts[0].ParentGroup.areUpdatesSuspended = true;
7292 foreach (SceneObjectPart part in parts)
7293 SetPrimParams(part, rules);
7294 }
7295 finally
7296 {
7297 parts[0].ParentGroup.areUpdatesSuspended = false;
7298 }
7299 }
7300 if (avatars.Count > 0)
7301 {
7302 foreach (ScenePresence avatar in avatars)
7303 SetPrimParams(avatar, rules);
7304 }
7305 }
6903 7306
6904 foreach (SceneObjectPart part in parts) 7307 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
6905 SetPrimParams(part, rules); 7308 {
6906 7309 llSetLinkPrimitiveParamsFast(linknumber, rules);
6907 ScriptSleep(200); 7310 ScriptSleep(200);
6908 } 7311 }
6909 7312
6910 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) 7313 protected void SetPrimParams(ScenePresence av, LSL_List rules)
6911 { 7314 {
6912 m_host.AddScriptLPS(1); 7315 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
7316 //We only support PRIM_POSITION and PRIM_ROTATION
6913 7317
6914 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7318 int idx = 0;
6915 7319
6916 foreach (SceneObjectPart part in parts) 7320 while (idx < rules.Length)
6917 SetPrimParams(part, rules); 7321 {
7322 int code = rules.GetLSLIntegerItem(idx++);
7323
7324 int remain = rules.Length - idx;
7325
7326
7327
7328 switch (code)
7329 {
7330 case (int)ScriptBaseClass.PRIM_POSITION:
7331 if (remain < 1)
7332 return;
7333 LSL_Vector v;
7334 v = rules.GetVector3Item(idx++);
7335 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
7336 av.SendAvatarDataToAllAgents();
7337
7338 break;
7339
7340 case (int)ScriptBaseClass.PRIM_ROTATION:
7341 if (remain < 1)
7342 return;
7343 LSL_Rotation r;
7344 r = rules.GetQuaternionItem(idx++);
7345 av.OffsetRotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
7346 av.SendAvatarDataToAllAgents();
7347 break;
7348 }
7349 }
6918 } 7350 }
6919 7351
6920 protected void SetPrimParams(SceneObjectPart part, LSL_List rules) 7352 protected void SetPrimParams(SceneObjectPart part, LSL_List rules)
6921 { 7353 {
7354 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7355 return;
7356
6922 int idx = 0; 7357 int idx = 0;
6923 7358
6924 while (idx < rules.Length) 7359 while (idx < rules.Length)
@@ -7453,13 +7888,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7453 public LSL_Integer llGetNumberOfPrims() 7888 public LSL_Integer llGetNumberOfPrims()
7454 { 7889 {
7455 m_host.AddScriptLPS(1); 7890 m_host.AddScriptLPS(1);
7456 int avatarCount = 0; 7891 int avatarCount = m_host.ParentGroup.GetLinkedAvatars().Count;
7457 World.ForEachScenePresence(delegate(ScenePresence presence) 7892
7458 {
7459 if (!presence.IsChildAgent && presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID))
7460 avatarCount++;
7461 });
7462
7463 return m_host.ParentGroup.PrimCount + avatarCount; 7893 return m_host.ParentGroup.PrimCount + avatarCount;
7464 } 7894 }
7465 7895
@@ -7475,55 +7905,98 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7475 m_host.AddScriptLPS(1); 7905 m_host.AddScriptLPS(1);
7476 UUID objID = UUID.Zero; 7906 UUID objID = UUID.Zero;
7477 LSL_List result = new LSL_List(); 7907 LSL_List result = new LSL_List();
7908
7909 // If the ID is not valid, return null result
7478 if (!UUID.TryParse(obj, out objID)) 7910 if (!UUID.TryParse(obj, out objID))
7479 { 7911 {
7480 result.Add(new LSL_Vector()); 7912 result.Add(new LSL_Vector());
7481 result.Add(new LSL_Vector()); 7913 result.Add(new LSL_Vector());
7482 return result; 7914 return result;
7483 } 7915 }
7916
7917 // Check if this is an attached prim. If so, replace
7918 // the UUID with the avatar UUID and report it's bounding box
7919 SceneObjectPart part = World.GetSceneObjectPart(objID);
7920 if (part != null && part.ParentGroup.IsAttachment)
7921 objID = part.ParentGroup.RootPart.AttachedAvatar;
7922
7923 // Find out if this is an avatar ID. If so, return it's box
7484 ScenePresence presence = World.GetScenePresence(objID); 7924 ScenePresence presence = World.GetScenePresence(objID);
7485 if (presence != null) 7925 if (presence != null)
7486 { 7926 {
7487 if (presence.ParentID == 0) // not sat on an object 7927 // As per LSL Wiki, there is no difference between sitting
7928 // and standing avatar since server 1.36
7929 LSL_Vector lower;
7930 LSL_Vector upper;
7931 if (presence.Animator.Animations.DefaultAnimation.AnimID
7932 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
7488 { 7933 {
7489 LSL_Vector lower; 7934 // This is for ground sitting avatars
7490 LSL_Vector upper; 7935 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7491 if (presence.Animator.Animations.DefaultAnimation.AnimID 7936 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7492 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) 7937 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7493 {
7494 // This is for ground sitting avatars
7495 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7496 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7497 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7498 }
7499 else
7500 {
7501 // This is for standing/flying avatars
7502 float height = presence.Appearance.AvatarHeight / 2.0f;
7503 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7504 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7505 }
7506 result.Add(lower);
7507 result.Add(upper);
7508 return result;
7509 } 7938 }
7510 else 7939 else
7511 { 7940 {
7512 // sitting on an object so we need the bounding box of that 7941 // This is for standing/flying avatars
7513 // which should include the avatar so set the UUID to the 7942 float height = presence.Appearance.AvatarHeight / 2.0f;
7514 // UUID of the object the avatar is sat on and allow it to fall through 7943 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7515 // to processing an object 7944 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7516 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
7517 objID = p.UUID;
7518 } 7945 }
7946
7947 // Adjust to the documented error offsets (see LSL Wiki)
7948 lower += new LSL_Vector(0.05f, 0.05f, 0.05f);
7949 upper -= new LSL_Vector(0.05f, 0.05f, 0.05f);
7950
7951 if (lower.x > upper.x)
7952 lower.x = upper.x;
7953 if (lower.y > upper.y)
7954 lower.y = upper.y;
7955 if (lower.z > upper.z)
7956 lower.z = upper.z;
7957
7958 result.Add(lower);
7959 result.Add(upper);
7960 return result;
7519 } 7961 }
7520 SceneObjectPart part = World.GetSceneObjectPart(objID); 7962
7963 part = World.GetSceneObjectPart(objID);
7521 // Currently only works for single prims without a sitting avatar 7964 // Currently only works for single prims without a sitting avatar
7522 if (part != null) 7965 if (part != null)
7523 { 7966 {
7524 Vector3 halfSize = part.Scale / 2.0f; 7967 float minX;
7525 LSL_Vector lower = new LSL_Vector(halfSize.X * -1.0f, halfSize.Y * -1.0f, halfSize.Z * -1.0f); 7968 float maxX;
7526 LSL_Vector upper = new LSL_Vector(halfSize.X, halfSize.Y, halfSize.Z); 7969 float minY;
7970 float maxY;
7971 float minZ;
7972 float maxZ;
7973
7974 // This BBox is in sim coordinates, with the offset being
7975 // a contained point.
7976 Vector3[] offsets = World.GetCombinedBoundingBox(new List<SceneObjectGroup> { part.ParentGroup },
7977 out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
7978
7979 minX -= offsets[0].X;
7980 maxX -= offsets[0].X;
7981 minY -= offsets[0].Y;
7982 maxY -= offsets[0].Y;
7983 minZ -= offsets[0].Z;
7984 maxZ -= offsets[0].Z;
7985
7986 LSL_Vector lower;
7987 LSL_Vector upper;
7988
7989 // Adjust to the documented error offsets (see LSL Wiki)
7990 lower = new LSL_Vector(minX + 0.05f, minY + 0.05f, minZ + 0.05f);
7991 upper = new LSL_Vector(maxX - 0.05f, maxY - 0.05f, maxZ - 0.05f);
7992
7993 if (lower.x > upper.x)
7994 lower.x = upper.x;
7995 if (lower.y > upper.y)
7996 lower.y = upper.y;
7997 if (lower.z > upper.z)
7998 lower.z = upper.z;
7999
7527 result.Add(lower); 8000 result.Add(lower);
7528 result.Add(upper); 8001 result.Add(upper);
7529 return result; 8002 return result;
@@ -7603,13 +8076,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7603 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, 8076 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
7604 part.AbsolutePosition.Y, 8077 part.AbsolutePosition.Y,
7605 part.AbsolutePosition.Z); 8078 part.AbsolutePosition.Z);
7606 // For some reason, the part.AbsolutePosition.* values do not change if the
7607 // linkset is rotated; they always reflect the child prim's world position
7608 // as though the linkset is unrotated. This is incompatible behavior with SL's
7609 // implementation, so will break scripts imported from there (not to mention it
7610 // makes it more difficult to determine a child prim's actual inworld position).
7611 if (part.ParentID != 0)
7612 v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
7613 res.Add(v); 8079 res.Add(v);
7614 break; 8080 break;
7615 8081
@@ -7770,56 +8236,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7770 case (int)ScriptBaseClass.PRIM_BUMP_SHINY: 8236 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7771 if (remain < 1) 8237 if (remain < 1)
7772 return res; 8238 return res;
7773 8239 face = (int)rules.GetLSLIntegerItem(idx++);
7774 face=(int)rules.GetLSLIntegerItem(idx++);
7775 8240
7776 tex = part.Shape.Textures; 8241 tex = part.Shape.Textures;
8242 int shiny;
7777 if (face == ScriptBaseClass.ALL_SIDES) 8243 if (face == ScriptBaseClass.ALL_SIDES)
7778 { 8244 {
7779 for (face = 0; face < GetNumberOfSides(part); face++) 8245 for (face = 0; face < GetNumberOfSides(part); face++)
7780 { 8246 {
7781 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8247 Shininess shinyness = tex.GetFace((uint)face).Shiny;
7782 // Convert Shininess to PRIM_SHINY_* 8248 if (shinyness == Shininess.High)
7783 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8249 {
7784 // PRIM_BUMP_* 8250 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
7785 res.Add(new LSL_Integer((int)texface.Bump)); 8251 }
8252 else if (shinyness == Shininess.Medium)
8253 {
8254 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8255 }
8256 else if (shinyness == Shininess.Low)
8257 {
8258 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8259 }
8260 else
8261 {
8262 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8263 }
8264 res.Add(new LSL_Integer(shiny));
8265 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
7786 } 8266 }
7787 } 8267 }
7788 else 8268 else
7789 { 8269 {
7790 if (face >= 0 && face < GetNumberOfSides(part)) 8270 Shininess shinyness = tex.GetFace((uint)face).Shiny;
8271 if (shinyness == Shininess.High)
7791 { 8272 {
7792 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8273 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
7793 // Convert Shininess to PRIM_SHINY_* 8274 }
7794 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8275 else if (shinyness == Shininess.Medium)
7795 // PRIM_BUMP_* 8276 {
7796 res.Add(new LSL_Integer((int)texface.Bump)); 8277 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
7797 } 8278 }
8279 else if (shinyness == Shininess.Low)
8280 {
8281 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8282 }
8283 else
8284 {
8285 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8286 }
8287 res.Add(new LSL_Integer(shiny));
8288 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
7798 } 8289 }
7799 break; 8290 break;
7800 8291
7801 case (int)ScriptBaseClass.PRIM_FULLBRIGHT: 8292 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7802 if (remain < 1) 8293 if (remain < 1)
7803 return res; 8294 return res;
7804 8295 face = (int)rules.GetLSLIntegerItem(idx++);
7805 face=(int)rules.GetLSLIntegerItem(idx++);
7806 8296
7807 tex = part.Shape.Textures; 8297 tex = part.Shape.Textures;
8298 int fullbright;
7808 if (face == ScriptBaseClass.ALL_SIDES) 8299 if (face == ScriptBaseClass.ALL_SIDES)
7809 { 8300 {
7810 for (face = 0; face < GetNumberOfSides(part); face++) 8301 for (face = 0; face < GetNumberOfSides(part); face++)
7811 { 8302 {
7812 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8303 if (tex.GetFace((uint)face).Fullbright == true)
7813 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); 8304 {
8305 fullbright = ScriptBaseClass.TRUE;
8306 }
8307 else
8308 {
8309 fullbright = ScriptBaseClass.FALSE;
8310 }
8311 res.Add(new LSL_Integer(fullbright));
7814 } 8312 }
7815 } 8313 }
7816 else 8314 else
7817 { 8315 {
7818 if (face >= 0 && face < GetNumberOfSides(part)) 8316 if (tex.GetFace((uint)face).Fullbright == true)
7819 { 8317 {
7820 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8318 fullbright = ScriptBaseClass.TRUE;
7821 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
7822 } 8319 }
8320 else
8321 {
8322 fullbright = ScriptBaseClass.FALSE;
8323 }
8324 res.Add(new LSL_Integer(fullbright));
7823 } 8325 }
7824 break; 8326 break;
7825 8327
@@ -7841,27 +8343,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7841 break; 8343 break;
7842 8344
7843 case (int)ScriptBaseClass.PRIM_TEXGEN: 8345 case (int)ScriptBaseClass.PRIM_TEXGEN:
8346 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
7844 if (remain < 1) 8347 if (remain < 1)
7845 return res; 8348 return res;
7846 8349 face = (int)rules.GetLSLIntegerItem(idx++);
7847 face=(int)rules.GetLSLIntegerItem(idx++);
7848 8350
7849 tex = part.Shape.Textures; 8351 tex = part.Shape.Textures;
7850 if (face == ScriptBaseClass.ALL_SIDES) 8352 if (face == ScriptBaseClass.ALL_SIDES)
7851 { 8353 {
7852 for (face = 0; face < GetNumberOfSides(part); face++) 8354 for (face = 0; face < GetNumberOfSides(part); face++)
7853 { 8355 {
7854 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8356 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
7855 // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc. 8357 {
7856 res.Add(new LSL_Integer((uint)texgen >> 1)); 8358 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8359 }
8360 else
8361 {
8362 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8363 }
7857 } 8364 }
7858 } 8365 }
7859 else 8366 else
7860 { 8367 {
7861 if (face >= 0 && face < GetNumberOfSides(part)) 8368 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
7862 { 8369 {
7863 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8370 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
7864 res.Add(new LSL_Integer((uint)texgen >> 1)); 8371 }
8372 else
8373 {
8374 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
7865 } 8375 }
7866 } 8376 }
7867 break; 8377 break;
@@ -7884,28 +8394,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7884 case (int)ScriptBaseClass.PRIM_GLOW: 8394 case (int)ScriptBaseClass.PRIM_GLOW:
7885 if (remain < 1) 8395 if (remain < 1)
7886 return res; 8396 return res;
7887 8397 face = (int)rules.GetLSLIntegerItem(idx++);
7888 face=(int)rules.GetLSLIntegerItem(idx++);
7889 8398
7890 tex = part.Shape.Textures; 8399 tex = part.Shape.Textures;
8400 float primglow;
7891 if (face == ScriptBaseClass.ALL_SIDES) 8401 if (face == ScriptBaseClass.ALL_SIDES)
7892 { 8402 {
7893 for (face = 0; face < GetNumberOfSides(part); face++) 8403 for (face = 0; face < GetNumberOfSides(part); face++)
7894 { 8404 {
7895 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8405 primglow = tex.GetFace((uint)face).Glow;
7896 res.Add(new LSL_Float(texface.Glow)); 8406 res.Add(new LSL_Float(primglow));
7897 } 8407 }
7898 } 8408 }
7899 else 8409 else
7900 { 8410 {
7901 if (face >= 0 && face < GetNumberOfSides(part)) 8411 primglow = tex.GetFace((uint)face).Glow;
7902 { 8412 res.Add(new LSL_Float(primglow));
7903 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
7904 res.Add(new LSL_Float(texface.Glow));
7905 }
7906 } 8413 }
7907 break; 8414 break;
7908
7909 case (int)ScriptBaseClass.PRIM_TEXT: 8415 case (int)ScriptBaseClass.PRIM_TEXT:
7910 Color4 textColor = part.GetTextColor(); 8416 Color4 textColor = part.GetTextColor();
7911 res.Add(part.Text); 8417 res.Add(part.Text);
@@ -8454,8 +8960,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8454 // The function returns an ordered list 8960 // The function returns an ordered list
8455 // representing the tokens found in the supplied 8961 // representing the tokens found in the supplied
8456 // sources string. If two successive tokenizers 8962 // sources string. If two successive tokenizers
8457 // are encountered, then a NULL entry is added 8963 // are encountered, then a null-string entry is
8458 // to the list. 8964 // added to the list.
8459 // 8965 //
8460 // It is a precondition that the source and 8966 // It is a precondition that the source and
8461 // toekizer lisst are non-null. If they are null, 8967 // toekizer lisst are non-null. If they are null,
@@ -8463,7 +8969,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8463 // while their lengths are being determined. 8969 // while their lengths are being determined.
8464 // 8970 //
8465 // A small amount of working memoryis required 8971 // A small amount of working memoryis required
8466 // of approximately 8*#tokenizers. 8972 // of approximately 8*#tokenizers + 8*srcstrlen.
8467 // 8973 //
8468 // There are many ways in which this function 8974 // There are many ways in which this function
8469 // can be implemented, this implementation is 8975 // can be implemented, this implementation is
@@ -8479,155 +8985,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8479 // and eliminates redundant tokenizers as soon 8985 // and eliminates redundant tokenizers as soon
8480 // as is possible. 8986 // as is possible.
8481 // 8987 //
8482 // The implementation tries to avoid any copying 8988 // The implementation tries to minimize temporary
8483 // of arrays or other objects. 8989 // garbage generation.
8484 // </remarks> 8990 // </remarks>
8485 8991
8486 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls) 8992 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8487 { 8993 {
8488 int beginning = 0; 8994 return ParseString2List(src, separators, spacers, true);
8489 int srclen = src.Length; 8995 }
8490 int seplen = separators.Length;
8491 object[] separray = separators.Data;
8492 int spclen = spacers.Length;
8493 object[] spcarray = spacers.Data;
8494 int mlen = seplen+spclen;
8495
8496 int[] offset = new int[mlen+1];
8497 bool[] active = new bool[mlen];
8498
8499 int best;
8500 int j;
8501
8502 // Initial capacity reduces resize cost
8503 8996
8504 LSL_List tokens = new LSL_List(); 8997 private LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
8998 {
8999 int srclen = src.Length;
9000 int seplen = separators.Length;
9001 object[] separray = separators.Data;
9002 int spclen = spacers.Length;
9003 object[] spcarray = spacers.Data;
9004 int dellen = 0;
9005 string[] delarray = new string[seplen+spclen];
8505 9006
8506 // All entries are initially valid 9007 int outlen = 0;
9008 string[] outarray = new string[srclen*2+1];
8507 9009
8508 for (int i = 0; i < mlen; i++) 9010 int i, j;
8509 active[i] = true; 9011 string d;
8510 9012
8511 offset[mlen] = srclen; 9013 m_host.AddScriptLPS(1);
8512 9014
8513 while (beginning < srclen) 9015 /*
9016 * Convert separator and spacer lists to C# strings.
9017 * Also filter out null strings so we don't hang.
9018 */
9019 for (i = 0; i < seplen; i ++)
8514 { 9020 {
9021 d = separray[i].ToString();
9022 if (d.Length > 0)
9023 {
9024 delarray[dellen++] = d;
9025 }
9026 }
9027 seplen = dellen;
8515 9028
8516 best = mlen; // as bad as it gets 9029 for (i = 0; i < spclen; i ++)
9030 {
9031 d = spcarray[i].ToString();
9032 if (d.Length > 0)
9033 {
9034 delarray[dellen++] = d;
9035 }
9036 }
8517 9037
8518 // Scan for separators 9038 /*
9039 * Scan through source string from beginning to end.
9040 */
9041 for (i = 0;;)
9042 {
8519 9043
8520 for (j = 0; j < seplen; j++) 9044 /*
9045 * Find earliest delimeter in src starting at i (if any).
9046 */
9047 int earliestDel = -1;
9048 int earliestSrc = srclen;
9049 string earliestStr = null;
9050 for (j = 0; j < dellen; j ++)
8521 { 9051 {
8522 if (separray[j].ToString() == String.Empty) 9052 d = delarray[j];
8523 active[j] = false; 9053 if (d != null)
8524
8525 if (active[j])
8526 { 9054 {
8527 // scan all of the markers 9055 int index = src.IndexOf(d, i);
8528 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1) 9056 if (index < 0)
8529 { 9057 {
8530 // not present at all 9058 delarray[j] = null; // delim nowhere in src, don't check it anymore
8531 active[j] = false;
8532 } 9059 }
8533 else 9060 else if (index < earliestSrc)
8534 { 9061 {
8535 // present and correct 9062 earliestSrc = index; // where delimeter starts in source string
8536 if (offset[j] < offset[best]) 9063 earliestDel = j; // where delimeter is in delarray[]
8537 { 9064 earliestStr = d; // the delimeter string from delarray[]
8538 // closest so far 9065 if (index == i) break; // can't do any better than found at beg of string
8539 best = j;
8540 if (offset[best] == beginning)
8541 break;
8542 }
8543 } 9066 }
8544 } 9067 }
8545 } 9068 }
8546 9069
8547 // Scan for spacers 9070 /*
8548 9071 * Output source string starting at i through start of earliest delimeter.
8549 if (offset[best] != beginning) 9072 */
9073 if (keepNulls || (earliestSrc > i))
8550 { 9074 {
8551 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++) 9075 outarray[outlen++] = src.Substring(i, earliestSrc - i);
8552 {
8553 if (spcarray[j-seplen].ToString() == String.Empty)
8554 active[j] = false;
8555
8556 if (active[j])
8557 {
8558 // scan all of the markers
8559 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
8560 {
8561 // not present at all
8562 active[j] = false;
8563 }
8564 else
8565 {
8566 // present and correct
8567 if (offset[j] < offset[best])
8568 {
8569 // closest so far
8570 best = j;
8571 }
8572 }
8573 }
8574 }
8575 } 9076 }
8576 9077
8577 // This is the normal exit from the scanning loop 9078 /*
9079 * If no delimeter found at or after i, we're done scanning.
9080 */
9081 if (earliestDel < 0) break;
8578 9082
8579 if (best == mlen) 9083 /*
9084 * If delimeter was a spacer, output the spacer.
9085 */
9086 if (earliestDel >= seplen)
8580 { 9087 {
8581 // no markers were found on this pass 9088 outarray[outlen++] = earliestStr;
8582 // so we're pretty much done
8583 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
8584 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
8585 break;
8586 } 9089 }
8587 9090
8588 // Otherwise we just add the newly delimited token 9091 /*
8589 // and recalculate where the search should continue. 9092 * Look at rest of src string following delimeter.
8590 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0)) 9093 */
8591 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning))); 9094 i = earliestSrc + earliestStr.Length;
8592
8593 if (best < seplen)
8594 {
8595 beginning = offset[best] + (separray[best].ToString()).Length;
8596 }
8597 else
8598 {
8599 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
8600 string str = spcarray[best - seplen].ToString();
8601 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
8602 tokens.Add(new LSL_String(str));
8603 }
8604 } 9095 }
8605 9096
8606 // This an awkward an not very intuitive boundary case. If the 9097 /*
8607 // last substring is a tokenizer, then there is an implied trailing 9098 * Make up an exact-sized output array suitable for an LSL_List object.
8608 // null list entry. Hopefully the single comparison will not be too 9099 */
8609 // arduous. Alternatively the 'break' could be replced with a return 9100 object[] outlist = new object[outlen];
8610 // but that's shabby programming. 9101 for (i = 0; i < outlen; i ++)
8611
8612 if ((beginning == srclen) && (keepNulls))
8613 { 9102 {
8614 if (srclen != 0) 9103 outlist[i] = new LSL_String(outarray[i]);
8615 tokens.Add(new LSL_String(""));
8616 } 9104 }
8617 9105 return new LSL_List(outlist);
8618 return tokens;
8619 }
8620
8621 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
8622 {
8623 m_host.AddScriptLPS(1);
8624 return this.ParseString(src, separators, spacers, false);
8625 }
8626
8627 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8628 {
8629 m_host.AddScriptLPS(1);
8630 return this.ParseString(src, separators, spacers, true);
8631 } 9106 }
8632 9107
8633 public LSL_Integer llGetObjectPermMask(int mask) 9108 public LSL_Integer llGetObjectPermMask(int mask)
@@ -8704,28 +9179,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8704 { 9179 {
8705 m_host.AddScriptLPS(1); 9180 m_host.AddScriptLPS(1);
8706 9181
8707 lock (m_host.TaskInventory) 9182 m_host.TaskInventory.LockItemsForRead(true);
9183 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8708 { 9184 {
8709 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9185 if (inv.Value.Name == item)
8710 { 9186 {
8711 if (inv.Value.Name == item) 9187 m_host.TaskInventory.LockItemsForRead(false);
9188 switch (mask)
8712 { 9189 {
8713 switch (mask) 9190 case 0:
8714 { 9191 return (int)inv.Value.BasePermissions;
8715 case 0: 9192 case 1:
8716 return (int)inv.Value.BasePermissions; 9193 return (int)inv.Value.CurrentPermissions;
8717 case 1: 9194 case 2:
8718 return (int)inv.Value.CurrentPermissions; 9195 return (int)inv.Value.GroupPermissions;
8719 case 2: 9196 case 3:
8720 return (int)inv.Value.GroupPermissions; 9197 return (int)inv.Value.EveryonePermissions;
8721 case 3: 9198 case 4:
8722 return (int)inv.Value.EveryonePermissions; 9199 return (int)inv.Value.NextPermissions;
8723 case 4:
8724 return (int)inv.Value.NextPermissions;
8725 }
8726 } 9200 }
8727 } 9201 }
8728 } 9202 }
9203 m_host.TaskInventory.LockItemsForRead(false);
8729 9204
8730 return -1; 9205 return -1;
8731 } 9206 }
@@ -8772,16 +9247,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8772 { 9247 {
8773 m_host.AddScriptLPS(1); 9248 m_host.AddScriptLPS(1);
8774 9249
8775 lock (m_host.TaskInventory) 9250 m_host.TaskInventory.LockItemsForRead(true);
9251 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8776 { 9252 {
8777 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9253 if (inv.Value.Name == item)
8778 { 9254 {
8779 if (inv.Value.Name == item) 9255 m_host.TaskInventory.LockItemsForRead(false);
8780 { 9256 return inv.Value.CreatorID.ToString();
8781 return inv.Value.CreatorID.ToString();
8782 }
8783 } 9257 }
8784 } 9258 }
9259 m_host.TaskInventory.LockItemsForRead(false);
8785 9260
8786 llSay(0, "No item name '" + item + "'"); 9261 llSay(0, "No item name '" + item + "'");
8787 9262
@@ -9046,17 +9521,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9046 int width = 0; 9521 int width = 0;
9047 int height = 0; 9522 int height = 0;
9048 9523
9049 ParcelMediaCommandEnum? commandToSend = null; 9524 uint commandToSend = 0;
9050 float time = 0.0f; // default is from start 9525 float time = 0.0f; // default is from start
9051 9526
9052 ScenePresence presence = null; 9527 ScenePresence presence = null;
9053 9528
9054 for (int i = 0; i < commandList.Data.Length; i++) 9529 for (int i = 0; i < commandList.Data.Length; i++)
9055 { 9530 {
9056 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i]; 9531 uint command = (uint)(commandList.GetLSLIntegerItem(i));
9057 switch (command) 9532 switch (command)
9058 { 9533 {
9059 case ParcelMediaCommandEnum.Agent: 9534 case (uint)ParcelMediaCommandEnum.Agent:
9060 // we send only to one agent 9535 // we send only to one agent
9061 if ((i + 1) < commandList.Length) 9536 if ((i + 1) < commandList.Length)
9062 { 9537 {
@@ -9073,25 +9548,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9073 } 9548 }
9074 break; 9549 break;
9075 9550
9076 case ParcelMediaCommandEnum.Loop: 9551 case (uint)ParcelMediaCommandEnum.Loop:
9077 loop = 1; 9552 loop = 1;
9078 commandToSend = command; 9553 commandToSend = command;
9079 update = true; //need to send the media update packet to set looping 9554 update = true; //need to send the media update packet to set looping
9080 break; 9555 break;
9081 9556
9082 case ParcelMediaCommandEnum.Play: 9557 case (uint)ParcelMediaCommandEnum.Play:
9083 loop = 0; 9558 loop = 0;
9084 commandToSend = command; 9559 commandToSend = command;
9085 update = true; //need to send the media update packet to make sure it doesn't loop 9560 update = true; //need to send the media update packet to make sure it doesn't loop
9086 break; 9561 break;
9087 9562
9088 case ParcelMediaCommandEnum.Pause: 9563 case (uint)ParcelMediaCommandEnum.Pause:
9089 case ParcelMediaCommandEnum.Stop: 9564 case (uint)ParcelMediaCommandEnum.Stop:
9090 case ParcelMediaCommandEnum.Unload: 9565 case (uint)ParcelMediaCommandEnum.Unload:
9091 commandToSend = command; 9566 commandToSend = command;
9092 break; 9567 break;
9093 9568
9094 case ParcelMediaCommandEnum.Url: 9569 case (uint)ParcelMediaCommandEnum.Url:
9095 if ((i + 1) < commandList.Length) 9570 if ((i + 1) < commandList.Length)
9096 { 9571 {
9097 if (commandList.Data[i + 1] is LSL_String) 9572 if (commandList.Data[i + 1] is LSL_String)
@@ -9104,7 +9579,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9104 } 9579 }
9105 break; 9580 break;
9106 9581
9107 case ParcelMediaCommandEnum.Texture: 9582 case (uint)ParcelMediaCommandEnum.Texture:
9108 if ((i + 1) < commandList.Length) 9583 if ((i + 1) < commandList.Length)
9109 { 9584 {
9110 if (commandList.Data[i + 1] is LSL_String) 9585 if (commandList.Data[i + 1] is LSL_String)
@@ -9117,7 +9592,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9117 } 9592 }
9118 break; 9593 break;
9119 9594
9120 case ParcelMediaCommandEnum.Time: 9595 case (uint)ParcelMediaCommandEnum.Time:
9121 if ((i + 1) < commandList.Length) 9596 if ((i + 1) < commandList.Length)
9122 { 9597 {
9123 if (commandList.Data[i + 1] is LSL_Float) 9598 if (commandList.Data[i + 1] is LSL_Float)
@@ -9129,7 +9604,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9129 } 9604 }
9130 break; 9605 break;
9131 9606
9132 case ParcelMediaCommandEnum.AutoAlign: 9607 case (uint)ParcelMediaCommandEnum.AutoAlign:
9133 if ((i + 1) < commandList.Length) 9608 if ((i + 1) < commandList.Length)
9134 { 9609 {
9135 if (commandList.Data[i + 1] is LSL_Integer) 9610 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9143,7 +9618,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9143 } 9618 }
9144 break; 9619 break;
9145 9620
9146 case ParcelMediaCommandEnum.Type: 9621 case (uint)ParcelMediaCommandEnum.Type:
9147 if ((i + 1) < commandList.Length) 9622 if ((i + 1) < commandList.Length)
9148 { 9623 {
9149 if (commandList.Data[i + 1] is LSL_String) 9624 if (commandList.Data[i + 1] is LSL_String)
@@ -9156,7 +9631,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9156 } 9631 }
9157 break; 9632 break;
9158 9633
9159 case ParcelMediaCommandEnum.Desc: 9634 case (uint)ParcelMediaCommandEnum.Desc:
9160 if ((i + 1) < commandList.Length) 9635 if ((i + 1) < commandList.Length)
9161 { 9636 {
9162 if (commandList.Data[i + 1] is LSL_String) 9637 if (commandList.Data[i + 1] is LSL_String)
@@ -9169,7 +9644,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9169 } 9644 }
9170 break; 9645 break;
9171 9646
9172 case ParcelMediaCommandEnum.Size: 9647 case (uint)ParcelMediaCommandEnum.Size:
9173 if ((i + 2) < commandList.Length) 9648 if ((i + 2) < commandList.Length)
9174 { 9649 {
9175 if (commandList.Data[i + 1] is LSL_Integer) 9650 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9239,7 +9714,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9239 } 9714 }
9240 } 9715 }
9241 9716
9242 if (commandToSend != null) 9717 if (commandToSend != 0)
9243 { 9718 {
9244 // the commandList contained a start/stop/... command, too 9719 // the commandList contained a start/stop/... command, too
9245 if (presence == null) 9720 if (presence == null)
@@ -9276,7 +9751,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9276 9751
9277 if (aList.Data[i] != null) 9752 if (aList.Data[i] != null)
9278 { 9753 {
9279 switch ((ParcelMediaCommandEnum) aList.Data[i]) 9754 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
9280 { 9755 {
9281 case ParcelMediaCommandEnum.Url: 9756 case ParcelMediaCommandEnum.Url:
9282 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL)); 9757 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
@@ -9319,16 +9794,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9319 { 9794 {
9320 m_host.AddScriptLPS(1); 9795 m_host.AddScriptLPS(1);
9321 9796
9322 lock (m_host.TaskInventory) 9797 m_host.TaskInventory.LockItemsForRead(true);
9798 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
9323 { 9799 {
9324 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9800 if (inv.Value.Name == name)
9325 { 9801 {
9326 if (inv.Value.Name == name) 9802 m_host.TaskInventory.LockItemsForRead(false);
9327 { 9803 return inv.Value.Type;
9328 return inv.Value.Type;
9329 }
9330 } 9804 }
9331 } 9805 }
9806 m_host.TaskInventory.LockItemsForRead(false);
9332 9807
9333 return -1; 9808 return -1;
9334 } 9809 }
@@ -9339,15 +9814,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9339 9814
9340 if (quick_pay_buttons.Data.Length < 4) 9815 if (quick_pay_buttons.Data.Length < 4)
9341 { 9816 {
9342 LSLError("List must have at least 4 elements"); 9817 int x;
9343 return; 9818 for (x=quick_pay_buttons.Data.Length; x<= 4; x++)
9819 {
9820 quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE);
9821 }
9344 } 9822 }
9345 m_host.ParentGroup.RootPart.PayPrice[0]=price; 9823 int[] nPrice = new int[5];
9346 9824 nPrice[0] = price;
9347 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; 9825 nPrice[1] = quick_pay_buttons.GetLSLIntegerItem(0);
9348 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; 9826 nPrice[2] = quick_pay_buttons.GetLSLIntegerItem(1);
9349 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; 9827 nPrice[3] = quick_pay_buttons.GetLSLIntegerItem(2);
9350 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; 9828 nPrice[4] = quick_pay_buttons.GetLSLIntegerItem(3);
9829 m_host.ParentGroup.RootPart.PayPrice = nPrice;
9351 m_host.ParentGroup.HasGroupChanged = true; 9830 m_host.ParentGroup.HasGroupChanged = true;
9352 } 9831 }
9353 9832
@@ -9359,17 +9838,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9359 if (invItemID == UUID.Zero) 9838 if (invItemID == UUID.Zero)
9360 return new LSL_Vector(); 9839 return new LSL_Vector();
9361 9840
9362 lock (m_host.TaskInventory) 9841 m_host.TaskInventory.LockItemsForRead(true);
9842 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9363 { 9843 {
9364 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9844 m_host.TaskInventory.LockItemsForRead(false);
9365 return new LSL_Vector(); 9845 return new LSL_Vector();
9846 }
9366 9847
9367 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 9848 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9368 { 9849 {
9369 ShoutError("No permissions to track the camera"); 9850 ShoutError("No permissions to track the camera");
9370 return new LSL_Vector(); 9851 m_host.TaskInventory.LockItemsForRead(false);
9371 } 9852 return new LSL_Vector();
9372 } 9853 }
9854 m_host.TaskInventory.LockItemsForRead(false);
9373 9855
9374 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9856 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9375 if (presence != null) 9857 if (presence != null)
@@ -9387,17 +9869,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9387 if (invItemID == UUID.Zero) 9869 if (invItemID == UUID.Zero)
9388 return new LSL_Rotation(); 9870 return new LSL_Rotation();
9389 9871
9390 lock (m_host.TaskInventory) 9872 m_host.TaskInventory.LockItemsForRead(true);
9873 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9391 { 9874 {
9392 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9875 m_host.TaskInventory.LockItemsForRead(false);
9393 return new LSL_Rotation(); 9876 return new LSL_Rotation();
9394
9395 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9396 {
9397 ShoutError("No permissions to track the camera");
9398 return new LSL_Rotation();
9399 }
9400 } 9877 }
9878 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9879 {
9880 ShoutError("No permissions to track the camera");
9881 m_host.TaskInventory.LockItemsForRead(false);
9882 return new LSL_Rotation();
9883 }
9884 m_host.TaskInventory.LockItemsForRead(false);
9401 9885
9402 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9886 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9403 if (presence != null) 9887 if (presence != null)
@@ -9459,8 +9943,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9459 { 9943 {
9460 m_host.AddScriptLPS(1); 9944 m_host.AddScriptLPS(1);
9461 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0); 9945 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0);
9462 if (detectedParams == null) return; // only works on the first detected avatar 9946 if (detectedParams == null)
9463 9947 {
9948 if (m_host.IsAttachment == true)
9949 {
9950 detectedParams = new DetectParams();
9951 detectedParams.Key = m_host.OwnerID;
9952 }
9953 else
9954 {
9955 return;
9956 }
9957 }
9958
9464 ScenePresence avatar = World.GetScenePresence(detectedParams.Key); 9959 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
9465 if (avatar != null) 9960 if (avatar != null)
9466 { 9961 {
@@ -9468,6 +9963,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9468 new Vector3((float)pos.x, (float)pos.y, (float)pos.z), 9963 new Vector3((float)pos.x, (float)pos.y, (float)pos.z),
9469 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z)); 9964 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z));
9470 } 9965 }
9966
9471 ScriptSleep(1000); 9967 ScriptSleep(1000);
9472 } 9968 }
9473 9969
@@ -9560,14 +10056,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9560 if (objectID == UUID.Zero) return; 10056 if (objectID == UUID.Zero) return;
9561 10057
9562 UUID agentID; 10058 UUID agentID;
9563 lock (m_host.TaskInventory) 10059 m_host.TaskInventory.LockItemsForRead(true);
9564 { 10060 // we need the permission first, to know which avatar we want to set the camera for
9565 // we need the permission first, to know which avatar we want to set the camera for 10061 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9566 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9567 10062
9568 if (agentID == UUID.Zero) return; 10063 if (agentID == UUID.Zero)
9569 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; 10064 {
10065 m_host.TaskInventory.LockItemsForRead(false);
10066 return;
9570 } 10067 }
10068 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10069 {
10070 m_host.TaskInventory.LockItemsForRead(false);
10071 return;
10072 }
10073 m_host.TaskInventory.LockItemsForRead(false);
9571 10074
9572 ScenePresence presence = World.GetScenePresence(agentID); 10075 ScenePresence presence = World.GetScenePresence(agentID);
9573 10076
@@ -9576,12 +10079,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9576 10079
9577 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>(); 10080 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
9578 object[] data = rules.Data; 10081 object[] data = rules.Data;
9579 for (int i = 0; i < data.Length; ++i) { 10082 for (int i = 0; i < data.Length; ++i)
10083 {
9580 int type = Convert.ToInt32(data[i++].ToString()); 10084 int type = Convert.ToInt32(data[i++].ToString());
9581 if (i >= data.Length) break; // odd number of entries => ignore the last 10085 if (i >= data.Length) break; // odd number of entries => ignore the last
9582 10086
9583 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3) 10087 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
9584 switch (type) { 10088 switch (type)
10089 {
9585 case ScriptBaseClass.CAMERA_FOCUS: 10090 case ScriptBaseClass.CAMERA_FOCUS:
9586 case ScriptBaseClass.CAMERA_FOCUS_OFFSET: 10091 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
9587 case ScriptBaseClass.CAMERA_POSITION: 10092 case ScriptBaseClass.CAMERA_POSITION:
@@ -9617,12 +10122,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9617 10122
9618 // we need the permission first, to know which avatar we want to clear the camera for 10123 // we need the permission first, to know which avatar we want to clear the camera for
9619 UUID agentID; 10124 UUID agentID;
9620 lock (m_host.TaskInventory) 10125 m_host.TaskInventory.LockItemsForRead(true);
10126 agentID = m_host.TaskInventory[invItemID].PermsGranter;
10127 if (agentID == UUID.Zero)
9621 { 10128 {
9622 agentID = m_host.TaskInventory[invItemID].PermsGranter; 10129 m_host.TaskInventory.LockItemsForRead(false);
9623 if (agentID == UUID.Zero) return; 10130 return;
9624 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
9625 } 10131 }
10132 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10133 {
10134 m_host.TaskInventory.LockItemsForRead(false);
10135 return;
10136 }
10137 m_host.TaskInventory.LockItemsForRead(false);
9626 10138
9627 ScenePresence presence = World.GetScenePresence(agentID); 10139 ScenePresence presence = World.GetScenePresence(agentID);
9628 10140
@@ -9689,19 +10201,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9689 public LSL_String llXorBase64StringsCorrect(string str1, string str2) 10201 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
9690 { 10202 {
9691 m_host.AddScriptLPS(1); 10203 m_host.AddScriptLPS(1);
9692 string ret = String.Empty; 10204
9693 string src1 = llBase64ToString(str1); 10205 if (str1 == String.Empty)
9694 string src2 = llBase64ToString(str2); 10206 return String.Empty;
9695 int c = 0; 10207 if (str2 == String.Empty)
9696 for (int i = 0; i < src1.Length; i++) 10208 return str1;
10209
10210 int len = str2.Length;
10211 if ((len % 4) != 0) // LL is EVIL!!!!
9697 { 10212 {
9698 ret += (char) (src1[i] ^ src2[c]); 10213 while (str2.EndsWith("="))
10214 str2 = str2.Substring(0, str2.Length - 1);
10215
10216 len = str2.Length;
10217 int mod = len % 4;
9699 10218
9700 c++; 10219 if (mod == 1)
9701 if (c >= src2.Length) 10220 str2 = str2.Substring(0, str2.Length - 1);
9702 c = 0; 10221 else if (mod == 2)
10222 str2 += "==";
10223 else if (mod == 3)
10224 str2 += "=";
9703 } 10225 }
9704 return llStringToBase64(ret); 10226
10227 byte[] data1;
10228 byte[] data2;
10229 try
10230 {
10231 data1 = Convert.FromBase64String(str1);
10232 data2 = Convert.FromBase64String(str2);
10233 }
10234 catch (Exception)
10235 {
10236 return new LSL_String(String.Empty);
10237 }
10238
10239 byte[] d2 = new Byte[data1.Length];
10240 int pos = 0;
10241
10242 if (data1.Length <= data2.Length)
10243 {
10244 Array.Copy(data2, 0, d2, 0, data1.Length);
10245 }
10246 else
10247 {
10248 while (pos < data1.Length)
10249 {
10250 len = data1.Length - pos;
10251 if (len > data2.Length)
10252 len = data2.Length;
10253
10254 Array.Copy(data2, 0, d2, pos, len);
10255 pos += len;
10256 }
10257 }
10258
10259 for (pos = 0 ; pos < data1.Length ; pos++ )
10260 data1[pos] ^= d2[pos];
10261
10262 return Convert.ToBase64String(data1);
9705 } 10263 }
9706 10264
9707 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body) 10265 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
@@ -9760,12 +10318,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9760 Regex r = new Regex(authregex); 10318 Regex r = new Regex(authregex);
9761 int[] gnums = r.GetGroupNumbers(); 10319 int[] gnums = r.GetGroupNumbers();
9762 Match m = r.Match(url); 10320 Match m = r.Match(url);
9763 if (m.Success) { 10321 if (m.Success)
9764 for (int i = 1; i < gnums.Length; i++) { 10322 {
10323 for (int i = 1; i < gnums.Length; i++)
10324 {
9765 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]]; 10325 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
9766 //CaptureCollection cc = g.Captures; 10326 //CaptureCollection cc = g.Captures;
9767 } 10327 }
9768 if (m.Groups.Count == 5) { 10328 if (m.Groups.Count == 5)
10329 {
9769 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString()))); 10330 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
9770 url = m.Groups[1].ToString() + m.Groups[4].ToString(); 10331 url = m.Groups[1].ToString() + m.Groups[4].ToString();
9771 } 10332 }
@@ -10082,15 +10643,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10082 10643
10083 internal UUID ScriptByName(string name) 10644 internal UUID ScriptByName(string name)
10084 { 10645 {
10085 lock (m_host.TaskInventory) 10646 m_host.TaskInventory.LockItemsForRead(true);
10647
10648 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
10086 { 10649 {
10087 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 10650 if (item.Type == 10 && item.Name == name)
10088 { 10651 {
10089 if (item.Type == 10 && item.Name == name) 10652 m_host.TaskInventory.LockItemsForRead(false);
10090 return item.ItemID; 10653 return item.ItemID;
10091 } 10654 }
10092 } 10655 }
10093 10656
10657 m_host.TaskInventory.LockItemsForRead(false);
10658
10094 return UUID.Zero; 10659 return UUID.Zero;
10095 } 10660 }
10096 10661
@@ -10131,6 +10696,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10131 { 10696 {
10132 m_host.AddScriptLPS(1); 10697 m_host.AddScriptLPS(1);
10133 10698
10699 //Clone is thread safe
10134 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10700 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10135 10701
10136 UUID assetID = UUID.Zero; 10702 UUID assetID = UUID.Zero;
@@ -10193,6 +10759,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10193 { 10759 {
10194 m_host.AddScriptLPS(1); 10760 m_host.AddScriptLPS(1);
10195 10761
10762 //Clone is thread safe
10196 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10763 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10197 10764
10198 UUID assetID = UUID.Zero; 10765 UUID assetID = UUID.Zero;
@@ -10272,6 +10839,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10272 10839
10273 return GetLinkPrimitiveParams(obj, rules); 10840 return GetLinkPrimitiveParams(obj, rules);
10274 } 10841 }
10842
10843 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
10844 {
10845 List<SceneObjectPart> parts = GetLinkParts(link);
10846 if (parts.Count < 1)
10847 return 0;
10848
10849 return GetNumberOfSides(parts[0]);
10850 }
10275 } 10851 }
10276 10852
10277 public class NotecardCache 10853 public class NotecardCache
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index bca08fb..3f0393d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -129,6 +129,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
129 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; 129 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow;
130 internal float m_ScriptDelayFactor = 1.0f; 130 internal float m_ScriptDelayFactor = 1.0f;
131 internal float m_ScriptDistanceFactor = 1.0f; 131 internal float m_ScriptDistanceFactor = 1.0f;
132 internal bool m_debuggerSafe = false;
132 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >(); 133 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >();
133 134
134 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 135 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
@@ -137,6 +138,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
137 m_host = host; 138 m_host = host;
138 m_localID = localID; 139 m_localID = localID;
139 m_itemID = itemID; 140 m_itemID = itemID;
141 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
140 142
141 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) 143 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false))
142 m_OSFunctionsEnabled = true; 144 m_OSFunctionsEnabled = true;
@@ -195,7 +197,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
195 197
196 internal void OSSLError(string msg) 198 internal void OSSLError(string msg)
197 { 199 {
198 throw new Exception("OSSL Runtime Error: " + msg); 200 if (m_debuggerSafe)
201 {
202 OSSLShoutError(msg);
203 }
204 else
205 {
206 throw new Exception("OSSL Runtime Error: " + msg);
207 }
199 } 208 }
200 209
201 private void InitLSL() 210 private void InitLSL()
@@ -835,18 +844,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
835 if (target != null) 844 if (target != null)
836 { 845 {
837 UUID animID=UUID.Zero; 846 UUID animID=UUID.Zero;
838 lock (m_host.TaskInventory) 847 m_host.TaskInventory.LockItemsForRead(true);
848 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
839 { 849 {
840 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 850 if (inv.Value.Name == animation)
841 { 851 {
842 if (inv.Value.Name == animation) 852 if (inv.Value.Type == (int)AssetType.Animation)
843 { 853 animID = inv.Value.AssetID;
844 if (inv.Value.Type == (int)AssetType.Animation) 854 continue;
845 animID = inv.Value.AssetID;
846 continue;
847 }
848 } 855 }
849 } 856 }
857 m_host.TaskInventory.LockItemsForRead(false);
850 if (animID == UUID.Zero) 858 if (animID == UUID.Zero)
851 target.Animator.AddAnimation(animation, m_host.UUID); 859 target.Animator.AddAnimation(animation, m_host.UUID);
852 else 860 else
@@ -868,18 +876,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
868 if (target != null) 876 if (target != null)
869 { 877 {
870 UUID animID=UUID.Zero; 878 UUID animID=UUID.Zero;
871 lock (m_host.TaskInventory) 879 m_host.TaskInventory.LockItemsForRead(true);
880 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
872 { 881 {
873 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 882 if (inv.Value.Name == animation)
874 { 883 {
875 if (inv.Value.Name == animation) 884 if (inv.Value.Type == (int)AssetType.Animation)
876 { 885 animID = inv.Value.AssetID;
877 if (inv.Value.Type == (int)AssetType.Animation) 886 continue;
878 animID = inv.Value.AssetID;
879 continue;
880 }
881 } 887 }
882 } 888 }
889 m_host.TaskInventory.LockItemsForRead(false);
883 890
884 if (animID == UUID.Zero) 891 if (animID == UUID.Zero)
885 target.Animator.RemoveAnimation(animation); 892 target.Animator.RemoveAnimation(animation);
@@ -1772,6 +1779,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1772 1779
1773 if (!UUID.TryParse(name, out assetID)) 1780 if (!UUID.TryParse(name, out assetID))
1774 { 1781 {
1782 m_host.TaskInventory.LockItemsForRead(true);
1775 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1783 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1776 { 1784 {
1777 if (item.Type == 7 && item.Name == name) 1785 if (item.Type == 7 && item.Name == name)
@@ -1779,6 +1787,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1779 assetID = item.AssetID; 1787 assetID = item.AssetID;
1780 } 1788 }
1781 } 1789 }
1790 m_host.TaskInventory.LockItemsForRead(false);
1782 } 1791 }
1783 1792
1784 if (assetID == UUID.Zero) 1793 if (assetID == UUID.Zero)
@@ -1825,6 +1834,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1825 1834
1826 if (!UUID.TryParse(name, out assetID)) 1835 if (!UUID.TryParse(name, out assetID))
1827 { 1836 {
1837 m_host.TaskInventory.LockItemsForRead(true);
1828 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1838 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1829 { 1839 {
1830 if (item.Type == 7 && item.Name == name) 1840 if (item.Type == 7 && item.Name == name)
@@ -1832,6 +1842,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1832 assetID = item.AssetID; 1842 assetID = item.AssetID;
1833 } 1843 }
1834 } 1844 }
1845 m_host.TaskInventory.LockItemsForRead(false);
1835 } 1846 }
1836 1847
1837 if (assetID == UUID.Zero) 1848 if (assetID == UUID.Zero)
@@ -1882,6 +1893,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1882 1893
1883 if (!UUID.TryParse(name, out assetID)) 1894 if (!UUID.TryParse(name, out assetID))
1884 { 1895 {
1896 m_host.TaskInventory.LockItemsForRead(true);
1885 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1897 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1886 { 1898 {
1887 if (item.Type == 7 && item.Name == name) 1899 if (item.Type == 7 && item.Name == name)
@@ -1889,6 +1901,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1889 assetID = item.AssetID; 1901 assetID = item.AssetID;
1890 } 1902 }
1891 } 1903 }
1904 m_host.TaskInventory.LockItemsForRead(false);
1892 } 1905 }
1893 1906
1894 if (assetID == UUID.Zero) 1907 if (assetID == UUID.Zero)
@@ -2368,9 +2381,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2368 { 2381 {
2369 if (avatar.IsChildAgent == false) 2382 if (avatar.IsChildAgent == false)
2370 { 2383 {
2371 result.Add(avatar.UUID); 2384 result.Add(new LSL_Key(avatar.UUID.ToString()));
2372 result.Add(avatar.AbsolutePosition); 2385 result.Add(new LSL_Vector(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z));
2373 result.Add(avatar.Name); 2386 result.Add(new LSL_String(avatar.Name));
2374 } 2387 }
2375 } 2388 }
2376 }); 2389 });
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index fefbb35..c4f90d2 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -204,7 +204,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
204 // Is the sensor type is AGENT and not SCRIPTED then include agents 204 // Is the sensor type is AGENT and not SCRIPTED then include agents
205 if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0) 205 if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0)
206 { 206 {
207 sensedEntities.AddRange(doAgentSensor(ts)); 207 sensedEntities.AddRange(doAgentSensor(ts));
208 } 208 }
209 209
210 // If SCRIPTED or PASSIVE or ACTIVE check objects 210 // If SCRIPTED or PASSIVE or ACTIVE check objects
@@ -301,7 +301,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
301 float dy; 301 float dy;
302 float dz; 302 float dz;
303 303
304 Quaternion q = SensePoint.RotationOffset; 304// Quaternion q = SensePoint.RotationOffset;
305 Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation!
305 if (SensePoint.ParentGroup.RootPart.IsAttachment) 306 if (SensePoint.ParentGroup.RootPart.IsAttachment)
306 { 307 {
307 // In attachments, the sensor cone always orients with the 308 // In attachments, the sensor cone always orients with the
@@ -309,6 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
309 // in mouselook. 310 // in mouselook.
310 311
311 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar); 312 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
313 fromRegionPos = avatar.AbsolutePosition;
312 q = avatar.Rotation; 314 q = avatar.Rotation;
313 } 315 }
314 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 316 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
@@ -422,6 +424,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
422 SceneObjectPart SensePoint = ts.host; 424 SceneObjectPart SensePoint = ts.host;
423 Vector3 fromRegionPos = SensePoint.AbsolutePosition; 425 Vector3 fromRegionPos = SensePoint.AbsolutePosition;
424 Quaternion q = SensePoint.RotationOffset; 426 Quaternion q = SensePoint.RotationOffset;
427 if (SensePoint.ParentGroup.RootPart.IsAttachment)
428 {
429 // In attachments, the sensor cone always orients with the
430 // avatar rotation. This may include a nonzero elevation if
431 // in mouselook.
432
433 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
434 fromRegionPos = avatar.AbsolutePosition;
435 q = avatar.Rotation;
436 }
425 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 437 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
426 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); 438 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
427 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); 439 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
index eeb59d9..2fd33fe 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
@@ -109,25 +109,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
109 if (Timers.Count == 0) 109 if (Timers.Count == 0)
110 return; 110 return;
111 111
112 Dictionary<string, TimerClass>.ValueCollection tvals;
112 lock (TimerListLock) 113 lock (TimerListLock)
113 { 114 {
114 // Go through all timers 115 // Go through all timers
115 Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values; 116 tvals = Timers.Values;
116 foreach (TimerClass ts in tvals) 117 }
118
119 foreach (TimerClass ts in tvals)
120 {
121 // Time has passed?
122 if (ts.next < DateTime.Now.Ticks)
117 { 123 {
118 // Time has passed? 124 //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next);
119 if (ts.next < DateTime.Now.Ticks) 125 // Add it to queue
120 { 126 m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
121 //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); 127 new EventParams("timer", new Object[0],
122 // Add it to queue 128 new DetectParams[0]));
123 m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, 129 // set next interval
124 new EventParams("timer", new Object[0], 130
125 new DetectParams[0])); 131 //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
126 // set next interval 132 ts.next = DateTime.Now.Ticks + ts.interval;
127
128 //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
129 ts.next = DateTime.Now.Ticks + ts.interval;
130 }
131 } 133 }
132 } 134 }
133 } 135 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
index 561e3b3..bae7d4b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
@@ -398,6 +398,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
398 LSL_Vector llWind(LSL_Vector offset); 398 LSL_Vector llWind(LSL_Vector offset);
399 LSL_String llXorBase64Strings(string str1, string str2); 399 LSL_String llXorBase64Strings(string str1, string str2);
400 LSL_String llXorBase64StringsCorrect(string str1, string str2); 400 LSL_String llXorBase64StringsCorrect(string str1, string str2);
401 LSL_Integer llGetLinkNumberOfSides(LSL_Integer link);
401 402
402 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 403 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
403 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 404 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 63007c6..c08ad3b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -83,7 +83,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
83 // Avatar Info Commands 83 // Avatar Info Commands
84 string osGetAgentIP(string agent); 84 string osGetAgentIP(string agent);
85 LSL_List osGetAgents(); 85 LSL_List osGetAgents();
86 86
87 // Teleport commands 87 // Teleport commands
88 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 88 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
89 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 89 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/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 b3c4d95..93d544b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -279,6 +279,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
279 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART 279 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART
280 public const int CHANGED_MEDIA = 2048; 280 public const int CHANGED_MEDIA = 2048;
281 public const int CHANGED_ANIMATION = 16384; 281 public const int CHANGED_ANIMATION = 16384;
282 public const int CHANGED_POSITION = 32768;
282 public const int TYPE_INVALID = 0; 283 public const int TYPE_INVALID = 0;
283 public const int TYPE_INTEGER = 1; 284 public const int TYPE_INTEGER = 1;
284 public const int TYPE_FLOAT = 2; 285 public const int TYPE_FLOAT = 2;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
index 451163f..7c26824 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Diagnostics; //for [DebuggerNonUserCode]
29using System.Runtime.Remoting.Lifetime; 30using System.Runtime.Remoting.Lifetime;
30using System.Threading; 31using System.Threading;
31using System.Reflection; 32using System.Reflection;
@@ -309,6 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
309 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel); 310 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel);
310 } 311 }
311 312
313 [DebuggerNonUserCode]
312 public void llDie() 314 public void llDie()
313 { 315 {
314 m_LSL_Functions.llDie(); 316 m_LSL_Functions.llDie();
@@ -1847,5 +1849,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
1847 { 1849 {
1848 return m_LSL_Functions.llClearPrimMedia(face); 1850 return m_LSL_Functions.llClearPrimMedia(face);
1849 } 1851 }
1852
1853 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
1854 {
1855 return m_LSL_Functions.llGetLinkNumberOfSides(link);
1856 }
1850 } 1857 }
1851} 1858}
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/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 8e712b6..9548253 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.IO; 29using System.IO;
30using System.Diagnostics; //for [DebuggerNonUserCode]
30using System.Runtime.Remoting; 31using System.Runtime.Remoting;
31using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
32using System.Threading; 33using System.Threading;
@@ -55,7 +56,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
55{ 56{
56 public class ScriptInstance : MarshalByRefObject, IScriptInstance 57 public class ScriptInstance : MarshalByRefObject, IScriptInstance
57 { 58 {
58 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 60
60 private IScriptEngine m_Engine; 61 private IScriptEngine m_Engine;
61 private IScriptWorkItem m_CurrentResult = null; 62 private IScriptWorkItem m_CurrentResult = null;
@@ -238,13 +239,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
238 239
239 if (part != null) 240 if (part != null)
240 { 241 {
241 lock (part.TaskInventory) 242 part.TaskInventory.LockItemsForRead(true);
243 if (part.TaskInventory.ContainsKey(m_ItemID))
242 { 244 {
243 if (part.TaskInventory.ContainsKey(m_ItemID)) 245 m_thisScriptTask = part.TaskInventory[m_ItemID];
244 {
245 m_thisScriptTask = part.TaskInventory[m_ItemID];
246 }
247 } 246 }
247 part.TaskInventory.LockItemsForRead(false);
248 } 248 }
249 249
250 ApiManager am = new ApiManager(); 250 ApiManager am = new ApiManager();
@@ -271,9 +271,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
271 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 271 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
272// lease.Register(this); 272// lease.Register(this);
273 } 273 }
274 catch (Exception) 274 catch (Exception e)
275 { 275 {
276 // m_log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly); 276 m_log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly);
277 throw;
277 } 278 }
278 279
279 try 280 try
@@ -434,14 +435,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
434 { 435 {
435 int permsMask; 436 int permsMask;
436 UUID permsGranter; 437 UUID permsGranter;
437 lock (part.TaskInventory) 438 part.TaskInventory.LockItemsForRead(true);
439 if (!part.TaskInventory.ContainsKey(m_ItemID))
438 { 440 {
439 if (!part.TaskInventory.ContainsKey(m_ItemID)) 441 part.TaskInventory.LockItemsForRead(false);
440 return; 442 return;
441
442 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
443 permsMask = part.TaskInventory[m_ItemID].PermsMask;
444 } 443 }
444 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
445 permsMask = part.TaskInventory[m_ItemID].PermsMask;
446 part.TaskInventory.LockItemsForRead(false);
445 447
446 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) 448 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
447 { 449 {
@@ -550,6 +552,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
550 return true; 552 return true;
551 } 553 }
552 554
555 [DebuggerNonUserCode] //Prevents the debugger from farting in this function
553 public void SetState(string state) 556 public void SetState(string state)
554 { 557 {
555 if (state == State) 558 if (state == State)
@@ -561,7 +564,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
561 new DetectParams[0])); 564 new DetectParams[0]));
562 PostEvent(new EventParams("state_entry", new Object[0], 565 PostEvent(new EventParams("state_entry", new Object[0],
563 new DetectParams[0])); 566 new DetectParams[0]));
564 567
565 throw new EventAbortException(); 568 throw new EventAbortException();
566 } 569 }
567 570
@@ -644,14 +647,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
644 /// <returns></returns> 647 /// <returns></returns>
645 public object EventProcessor() 648 public object EventProcessor()
646 { 649 {
647 if (m_Suspended) 650 EventParams data = null;
648 return 0;
649 651
650 lock (m_Script) 652 lock (m_EventQueue)
651 { 653 {
652 EventParams data = null; 654 if (m_Suspended)
655 return 0;
653 656
654 lock (m_EventQueue) 657 lock (m_Script)
655 { 658 {
656 data = (EventParams) m_EventQueue.Dequeue(); 659 data = (EventParams) m_EventQueue.Dequeue();
657 if (data == null) // Shouldn't happen 660 if (data == null) // Shouldn't happen
@@ -677,6 +680,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
677 if (data.EventName == "collision") 680 if (data.EventName == "collision")
678 m_CollisionInQueue = false; 681 m_CollisionInQueue = false;
679 } 682 }
683 }
684 lock(m_Script)
685 {
680 686
681 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this); 687 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this);
682 688
@@ -833,6 +839,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
833 new Object[0], new DetectParams[0])); 839 new Object[0], new DetectParams[0]));
834 } 840 }
835 841
842 [DebuggerNonUserCode] //Stops the VS debugger from farting in this function
836 public void ApiResetScript() 843 public void ApiResetScript()
837 { 844 {
838 // bool running = Running; 845 // bool running = Running;
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index 91e03ac..5fd5bcf 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 }
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 8629674..35cc65b 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -30,6 +30,7 @@ using System.IO;
30using System.Threading; 30using System.Threading;
31using System.Collections; 31using System.Collections;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Diagnostics; //for [DebuggerNonUserCode]
33using System.Security; 34using System.Security;
34using System.Security.Policy; 35using System.Security.Policy;
35using System.Reflection; 36using System.Reflection;
@@ -103,6 +104,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
103 private Dictionary<UUID, IScriptInstance> m_Scripts = 104 private Dictionary<UUID, IScriptInstance> m_Scripts =
104 new Dictionary<UUID, IScriptInstance>(); 105 new Dictionary<UUID, IScriptInstance>();
105 106
107 private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
108
106 // Maps the asset ID to the assembly 109 // Maps the asset ID to the assembly
107 110
108 private Dictionary<UUID, string> m_Assemblies = 111 private Dictionary<UUID, string> m_Assemblies =
@@ -125,6 +128,71 @@ namespace OpenSim.Region.ScriptEngine.XEngine
125 IWorkItemResult m_CurrentCompile = null; 128 IWorkItemResult m_CurrentCompile = null;
126 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>(); 129 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
127 130
131 private void lockScriptsForRead(bool locked)
132 {
133 if (locked)
134 {
135 if (m_scriptsLock.RecursiveReadCount > 0)
136 {
137 m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
138 m_scriptsLock.ExitReadLock();
139 }
140 if (m_scriptsLock.RecursiveWriteCount > 0)
141 {
142 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
143 m_scriptsLock.ExitWriteLock();
144 }
145
146 while (!m_scriptsLock.TryEnterReadLock(60000))
147 {
148 m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire READ lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
149 if (m_scriptsLock.IsWriteLockHeld)
150 {
151 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
152 }
153 }
154 }
155 else
156 {
157 if (m_scriptsLock.RecursiveReadCount > 0)
158 {
159 m_scriptsLock.ExitReadLock();
160 }
161 }
162 }
163 private void lockScriptsForWrite(bool locked)
164 {
165 if (locked)
166 {
167 if (m_scriptsLock.RecursiveReadCount > 0)
168 {
169 m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
170 m_scriptsLock.ExitReadLock();
171 }
172 if (m_scriptsLock.RecursiveWriteCount > 0)
173 {
174 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
175 m_scriptsLock.ExitWriteLock();
176 }
177
178 while (!m_scriptsLock.TryEnterWriteLock(60000))
179 {
180 m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
181 if (m_scriptsLock.IsWriteLockHeld)
182 {
183 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
184 }
185 }
186 }
187 else
188 {
189 if (m_scriptsLock.RecursiveWriteCount > 0)
190 {
191 m_scriptsLock.ExitWriteLock();
192 }
193 }
194 }
195
128 public string ScriptEngineName 196 public string ScriptEngineName
129 { 197 {
130 get { return "XEngine"; } 198 get { return "XEngine"; }
@@ -270,43 +338,45 @@ namespace OpenSim.Region.ScriptEngine.XEngine
270 338
271 public void RemoveRegion(Scene scene) 339 public void RemoveRegion(Scene scene)
272 { 340 {
273 lock (m_Scripts) 341 lockScriptsForRead(true);
342 foreach (IScriptInstance instance in m_Scripts.Values)
274 { 343 {
275 foreach (IScriptInstance instance in m_Scripts.Values) 344 // Force a final state save
345 //
346 if (m_Assemblies.ContainsKey(instance.AssetID))
276 { 347 {
277 // Force a final state save 348 string assembly = m_Assemblies[instance.AssetID];
278 // 349 instance.SaveState(assembly);
279 if (m_Assemblies.ContainsKey(instance.AssetID)) 350 }
280 {
281 string assembly = m_Assemblies[instance.AssetID];
282 instance.SaveState(assembly);
283 }
284 351
285 // Clear the event queue and abort the instance thread 352 // Clear the event queue and abort the instance thread
286 // 353 //
287 instance.ClearQueue(); 354 instance.ClearQueue();
288 instance.Stop(0); 355 instance.Stop(0);
289 356
290 // Release events, timer, etc 357 // Release events, timer, etc
291 // 358 //
292 instance.DestroyScriptInstance(); 359 instance.DestroyScriptInstance();
293 360
294 // Unload scripts and app domains 361 // Unload scripts and app domains
295 // Must be done explicitly because they have infinite 362 // Must be done explicitly because they have infinite
296 // lifetime 363 // lifetime
297 // 364 //
298 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); 365 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
299 if (m_DomainScripts[instance.AppDomain].Count == 0) 366 if (m_DomainScripts[instance.AppDomain].Count == 0)
300 { 367 {
301 m_DomainScripts.Remove(instance.AppDomain); 368 m_DomainScripts.Remove(instance.AppDomain);
302 UnloadAppDomain(instance.AppDomain); 369 UnloadAppDomain(instance.AppDomain);
303 }
304 } 370 }
305 m_Scripts.Clear();
306 m_PrimObjects.Clear();
307 m_Assemblies.Clear();
308 m_DomainScripts.Clear();
309 } 371 }
372 lockScriptsForRead(false);
373 lockScriptsForWrite(true);
374 m_Scripts.Clear();
375 lockScriptsForWrite(false);
376 m_PrimObjects.Clear();
377 m_Assemblies.Clear();
378 m_DomainScripts.Clear();
379
310 lock (m_ScriptEngines) 380 lock (m_ScriptEngines)
311 { 381 {
312 m_ScriptEngines.Remove(this); 382 m_ScriptEngines.Remove(this);
@@ -365,22 +435,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
365 435
366 List<IScriptInstance> instances = new List<IScriptInstance>(); 436 List<IScriptInstance> instances = new List<IScriptInstance>();
367 437
368 lock (m_Scripts) 438 lockScriptsForRead(true);
369 { 439 foreach (IScriptInstance instance in m_Scripts.Values)
370 foreach (IScriptInstance instance in m_Scripts.Values)
371 instances.Add(instance); 440 instances.Add(instance);
372 } 441 lockScriptsForRead(false);
373 442
374 foreach (IScriptInstance i in instances) 443 foreach (IScriptInstance i in instances)
375 { 444 {
376 string assembly = String.Empty; 445 string assembly = String.Empty;
377 446
378 lock (m_Scripts) 447
379 {
380 if (!m_Assemblies.ContainsKey(i.AssetID)) 448 if (!m_Assemblies.ContainsKey(i.AssetID))
381 continue; 449 continue;
382 assembly = m_Assemblies[i.AssetID]; 450 assembly = m_Assemblies[i.AssetID];
383 } 451
384 452
385 i.SaveState(assembly); 453 i.SaveState(assembly);
386 } 454 }
@@ -709,92 +777,95 @@ namespace OpenSim.Region.ScriptEngine.XEngine
709 } 777 }
710 778
711 ScriptInstance instance = null; 779 ScriptInstance instance = null;
712 lock (m_Scripts) 780 // Create the object record
781 lockScriptsForRead(true);
782 if ((!m_Scripts.ContainsKey(itemID)) ||
783 (m_Scripts[itemID].AssetID != assetID))
713 { 784 {
714 // Create the object record 785 lockScriptsForRead(false);
715 786
716 if ((!m_Scripts.ContainsKey(itemID)) || 787 UUID appDomain = assetID;
717 (m_Scripts[itemID].AssetID != assetID))
718 {
719 UUID appDomain = assetID;
720 788
721 if (part.ParentGroup.IsAttachment) 789 if (part.ParentGroup.IsAttachment)
722 appDomain = part.ParentGroup.RootPart.UUID; 790 appDomain = part.ParentGroup.RootPart.UUID;
723 791
724 if (!m_AppDomains.ContainsKey(appDomain)) 792 if (!m_AppDomains.ContainsKey(appDomain))
793 {
794 try
725 { 795 {
726 try 796 AppDomainSetup appSetup = new AppDomainSetup();
727 { 797 appSetup.PrivateBinPath = Path.Combine(
728 AppDomainSetup appSetup = new AppDomainSetup(); 798 m_ScriptEnginesPath,
729 appSetup.PrivateBinPath = Path.Combine( 799 m_Scene.RegionInfo.RegionID.ToString());
730 m_ScriptEnginesPath, 800
731 m_Scene.RegionInfo.RegionID.ToString()); 801 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
732 802 Evidence evidence = new Evidence(baseEvidence);
733 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; 803
734 Evidence evidence = new Evidence(baseEvidence); 804 AppDomain sandbox;
735 805 if (m_AppDomainLoading)
736 AppDomain sandbox; 806 sandbox = AppDomain.CreateDomain(
737 if (m_AppDomainLoading) 807 m_Scene.RegionInfo.RegionID.ToString(),
738 sandbox = AppDomain.CreateDomain( 808 evidence, appSetup);
739 m_Scene.RegionInfo.RegionID.ToString(), 809 else
740 evidence, appSetup); 810 sandbox = AppDomain.CurrentDomain;
741 else 811
742 sandbox = AppDomain.CurrentDomain; 812 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
743 813 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
744 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 814 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
745 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 815 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
746 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); 816 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
747 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); 817 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
748 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); 818 //sandbox.SetAppDomainPolicy(sandboxPolicy);
749 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; 819
750 //sandbox.SetAppDomainPolicy(sandboxPolicy); 820 m_AppDomains[appDomain] = sandbox;
751 821
752 m_AppDomains[appDomain] = sandbox; 822 m_AppDomains[appDomain].AssemblyResolve +=
753 823 new ResolveEventHandler(
754 m_AppDomains[appDomain].AssemblyResolve += 824 AssemblyResolver.OnAssemblyResolve);
755 new ResolveEventHandler( 825 m_DomainScripts[appDomain] = new List<UUID>();
756 AssemblyResolver.OnAssemblyResolve); 826 }
757 m_DomainScripts[appDomain] = new List<UUID>(); 827 catch (Exception e)
758 } 828 {
759 catch (Exception e) 829 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
830 m_ScriptErrorMessage += "Exception creating app domain:\n";
831 m_ScriptFailCount++;
832 lock (m_AddingAssemblies)
760 { 833 {
761 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); 834 m_AddingAssemblies[assembly]--;
762 m_ScriptErrorMessage += "Exception creating app domain:\n";
763 m_ScriptFailCount++;
764 lock (m_AddingAssemblies)
765 {
766 m_AddingAssemblies[assembly]--;
767 }
768 return false;
769 } 835 }
836 return false;
770 } 837 }
771 m_DomainScripts[appDomain].Add(itemID); 838 }
772 839 m_DomainScripts[appDomain].Add(itemID);
773 instance = new ScriptInstance(this, part, 840
774 itemID, assetID, assembly, 841 instance = new ScriptInstance(this, part,
775 m_AppDomains[appDomain], 842 itemID, assetID, assembly,
776 part.ParentGroup.RootPart.Name, 843 m_AppDomains[appDomain],
777 item.Name, startParam, postOnRez, 844 part.ParentGroup.RootPart.Name,
778 stateSource, m_MaxScriptQueue); 845 item.Name, startParam, postOnRez,
779 846 stateSource, m_MaxScriptQueue);
780 m_log.DebugFormat( 847
848 m_log.DebugFormat(
781 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", 849 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
782 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, 850 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
783 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); 851 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
784 852
785 if (presence != null) 853 if (presence != null)
786 { 854 {
787 ShowScriptSaveResponse(item.OwnerID, 855 ShowScriptSaveResponse(item.OwnerID,
788 assetID, "Compile successful", true); 856 assetID, "Compile successful", true);
789 }
790
791 instance.AppDomain = appDomain;
792 instance.LineMap = linemap;
793
794 m_Scripts[itemID] = instance;
795 } 857 }
796 }
797 858
859 instance.AppDomain = appDomain;
860 instance.LineMap = linemap;
861 lockScriptsForWrite(true);
862 m_Scripts[itemID] = instance;
863 lockScriptsForWrite(false);
864 }
865 else
866 {
867 lockScriptsForRead(false);
868 }
798 lock (m_PrimObjects) 869 lock (m_PrimObjects)
799 { 870 {
800 if (!m_PrimObjects.ContainsKey(localID)) 871 if (!m_PrimObjects.ContainsKey(localID))
@@ -813,9 +884,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
813 m_AddingAssemblies[assembly]--; 884 m_AddingAssemblies[assembly]--;
814 } 885 }
815 886
816 if (instance != null) 887 if (instance!=null)
817 instance.Init(); 888 instance.Init();
818 889
819 return true; 890 return true;
820 } 891 }
821 892
@@ -828,20 +899,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine
828 m_CompileDict.Remove(itemID); 899 m_CompileDict.Remove(itemID);
829 } 900 }
830 901
831 IScriptInstance instance = null; 902 lockScriptsForRead(true);
832 903 // Do we even have it?
833 lock (m_Scripts) 904 if (!m_Scripts.ContainsKey(itemID))
834 { 905 {
835 // Do we even have it? 906 lockScriptsForRead(false);
836 if (!m_Scripts.ContainsKey(itemID)) 907 return;
837 return;
838
839 instance=m_Scripts[itemID];
840 m_Scripts.Remove(itemID);
841 } 908 }
909
842 910
911 IScriptInstance instance=m_Scripts[itemID];
912 lockScriptsForRead(false);
913 lockScriptsForWrite(true);
914 m_Scripts.Remove(itemID);
915 lockScriptsForWrite(false);
843 instance.ClearQueue(); 916 instance.ClearQueue();
844 instance.Stop(0); 917 instance.Stop(0);
918
845// bool objectRemoved = false; 919// bool objectRemoved = false;
846 920
847 lock (m_PrimObjects) 921 lock (m_PrimObjects)
@@ -877,11 +951,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
877 ObjectRemoved handlerObjectRemoved = OnObjectRemoved; 951 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
878 if (handlerObjectRemoved != null) 952 if (handlerObjectRemoved != null)
879 { 953 {
880 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); 954 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
881 handlerObjectRemoved(part.UUID); 955 handlerObjectRemoved(part.UUID);
882 } 956 }
883 957
884 958 CleanAssemblies();
959
885 ScriptRemoved handlerScriptRemoved = OnScriptRemoved; 960 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
886 if (handlerScriptRemoved != null) 961 if (handlerScriptRemoved != null)
887 handlerScriptRemoved(itemID); 962 handlerScriptRemoved(itemID);
@@ -1023,7 +1098,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1023 return false; 1098 return false;
1024 1099
1025 uuids = m_PrimObjects[localID]; 1100 uuids = m_PrimObjects[localID];
1026 } 1101
1027 1102
1028 foreach (UUID itemID in uuids) 1103 foreach (UUID itemID in uuids)
1029 { 1104 {
@@ -1041,6 +1116,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1041 result = true; 1116 result = true;
1042 } 1117 }
1043 } 1118 }
1119 }
1044 1120
1045 return result; 1121 return result;
1046 } 1122 }
@@ -1140,12 +1216,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1140 private IScriptInstance GetInstance(UUID itemID) 1216 private IScriptInstance GetInstance(UUID itemID)
1141 { 1217 {
1142 IScriptInstance instance; 1218 IScriptInstance instance;
1143 lock (m_Scripts) 1219 lockScriptsForRead(true);
1220 if (!m_Scripts.ContainsKey(itemID))
1144 { 1221 {
1145 if (!m_Scripts.ContainsKey(itemID)) 1222 lockScriptsForRead(false);
1146 return null; 1223 return null;
1147 instance = m_Scripts[itemID];
1148 } 1224 }
1225 instance = m_Scripts[itemID];
1226 lockScriptsForRead(false);
1149 return instance; 1227 return instance;
1150 } 1228 }
1151 1229
@@ -1169,6 +1247,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1169 return false; 1247 return false;
1170 } 1248 }
1171 1249
1250 [DebuggerNonUserCode]
1172 public void ApiResetScript(UUID itemID) 1251 public void ApiResetScript(UUID itemID)
1173 { 1252 {
1174 IScriptInstance instance = GetInstance(itemID); 1253 IScriptInstance instance = GetInstance(itemID);
@@ -1220,6 +1299,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1220 return UUID.Zero; 1299 return UUID.Zero;
1221 } 1300 }
1222 1301
1302 [DebuggerNonUserCode]
1223 public void SetState(UUID itemID, string newState) 1303 public void SetState(UUID itemID, string newState)
1224 { 1304 {
1225 IScriptInstance instance = GetInstance(itemID); 1305 IScriptInstance instance = GetInstance(itemID);
@@ -1240,11 +1320,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1240 { 1320 {
1241 List<IScriptInstance> instances = new List<IScriptInstance>(); 1321 List<IScriptInstance> instances = new List<IScriptInstance>();
1242 1322
1243 lock (m_Scripts) 1323 lockScriptsForRead(true);
1244 { 1324 foreach (IScriptInstance instance in m_Scripts.Values)
1245 foreach (IScriptInstance instance in m_Scripts.Values)
1246 instances.Add(instance); 1325 instances.Add(instance);
1247 } 1326 lockScriptsForRead(false);
1248 1327
1249 foreach (IScriptInstance i in instances) 1328 foreach (IScriptInstance i in instances)
1250 { 1329 {
diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs
index 00f035c..edb44ea 100644
--- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs
+++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs
@@ -408,6 +408,7 @@ namespace OpenSim.Server.Handlers.Asset
408 408
409 byte[] HandlePurgeFolder(Dictionary<string,object> request) 409 byte[] HandlePurgeFolder(Dictionary<string,object> request)
410 { 410 {
411
411 Dictionary<string,object> result = new Dictionary<string,object>(); 412 Dictionary<string,object> result = new Dictionary<string,object>();
412 UUID folderID = UUID.Zero; 413 UUID folderID = UUID.Zero;
413 UUID.TryParse(request["ID"].ToString(), out folderID); 414 UUID.TryParse(request["ID"].ToString(), out folderID);
diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
index 24ae81f..8aa410b 100644
--- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
+++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs
@@ -110,6 +110,11 @@ namespace OpenSim.Server.Handlers.Simulation
110 DoAgentDelete(request, responsedata, agentID, action, regionID); 110 DoAgentDelete(request, responsedata, agentID, action, regionID);
111 return responsedata; 111 return responsedata;
112 } 112 }
113 else if (method.Equals("DELETECHILD"))
114 {
115 DoChildAgentDelete(request, responsedata, agentID, action, regionID);
116 return responsedata;
117 }
113 else if (method.Equals("QUERYACCESSS")) 118 else if (method.Equals("QUERYACCESSS"))
114 { 119 {
115 DoQueryAccess(request, responsedata, agentID, regionID); 120 DoQueryAccess(request, responsedata, agentID, regionID);
@@ -378,6 +383,24 @@ namespace OpenSim.Server.Handlers.Simulation
378 } 383 }
379 } 384 }
380 385
386 protected void DoChildAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID)
387 {
388 m_log.Debug(" >>> DoChildAgentDelete action:" + action + "; RegionID:" + regionID);
389
390 GridRegion destination = new GridRegion();
391 destination.RegionID = regionID;
392
393 if (action.Equals("release"))
394 ReleaseAgent(regionID, id);
395 else
396 m_SimulationService.CloseChildAgent(destination, id);
397
398 responsedata["int_response_code"] = HttpStatusCode.OK;
399 responsedata["str_response_string"] = "OpenSim agent " + id.ToString();
400
401 m_log.Debug("[AGENT HANDLER]: Child Agent Released/Deleted.");
402 }
403
381 protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID) 404 protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID)
382 { 405 {
383 m_log.Debug(" >>> DoDelete action:" + action + "; RegionID:" + regionID); 406 m_log.Debug(" >>> DoDelete action:" + action + "; RegionID:" + regionID);
diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs
index 3fd2fcf..81ef225 100644
--- a/OpenSim/Services/AssetService/AssetService.cs
+++ b/OpenSim/Services/AssetService/AssetService.cs
@@ -151,7 +151,10 @@ namespace OpenSim.Services.AssetService
151 public virtual string Store(AssetBase asset) 151 public virtual string Store(AssetBase asset)
152 { 152 {
153 //m_log.DebugFormat("[ASSET SERVICE]: Store asset {0} {1}", asset.Name, asset.ID); 153 //m_log.DebugFormat("[ASSET SERVICE]: Store asset {0} {1}", asset.Name, asset.ID);
154 m_Database.StoreAsset(asset); 154 if (!m_Database.StoreAsset(asset))
155 {
156 return UUID.Zero.ToString();
157 }
155 158
156 return asset.ID; 159 return asset.ID;
157 } 160 }
diff --git a/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs b/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs
index edc1097..5980f0c 100644
--- a/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs
+++ b/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs
@@ -31,6 +31,8 @@ using log4net;
31using Nini.Config; 31using Nini.Config;
32using System.Reflection; 32using System.Reflection;
33using OpenSim.Services.Base; 33using OpenSim.Services.Base;
34using OpenSim.Server.Base;
35using OpenSim.Services.Interfaces;
34using OpenSim.Data; 36using OpenSim.Data;
35using OpenSim.Framework; 37using OpenSim.Framework;
36 38
@@ -49,6 +51,12 @@ namespace OpenSim.Services.AuthenticationService
49 MethodBase.GetCurrentMethod().DeclaringType); 51 MethodBase.GetCurrentMethod().DeclaringType);
50 52
51 protected IAuthenticationData m_Database; 53 protected IAuthenticationData m_Database;
54 protected IUserAccountService m_UserAccountService = null;
55
56 public AuthenticationServiceBase(IConfigSource config, IUserAccountService acct) : this(config)
57 {
58 m_UserAccountService = acct;
59 }
52 60
53 public AuthenticationServiceBase(IConfigSource config) : base(config) 61 public AuthenticationServiceBase(IConfigSource config) : base(config)
54 { 62 {
diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
index 17619ff..cf7496f 100644
--- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
+++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
@@ -51,6 +51,12 @@ namespace OpenSim.Services.AuthenticationService
51 LogManager.GetLogger( 51 LogManager.GetLogger(
52 MethodBase.GetCurrentMethod().DeclaringType); 52 MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 public PasswordAuthenticationService(IConfigSource config, IUserAccountService userService) :
55 base(config, userService)
56 {
57 m_log.Debug("[AUTH SERVICE]: Started with User Account access");
58 }
59
54 public PasswordAuthenticationService(IConfigSource config) : 60 public PasswordAuthenticationService(IConfigSource config) :
55 base(config) 61 base(config)
56 { 62 {
@@ -58,28 +64,70 @@ namespace OpenSim.Services.AuthenticationService
58 64
59 public string Authenticate(UUID principalID, string password, int lifetime) 65 public string Authenticate(UUID principalID, string password, int lifetime)
60 { 66 {
67 m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null);
61 AuthenticationData data = m_Database.Get(principalID); 68 AuthenticationData data = m_Database.Get(principalID);
69 UserAccount user = null;
70 if (m_UserAccountService != null)
71 user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID);
72
73 if (data == null || data.Data == null)
74 {
75 m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID);
76 return String.Empty;
77 }
78
79 if (!data.Data.ContainsKey("passwordHash") ||
80 !data.Data.ContainsKey("passwordSalt"))
81 {
82 return String.Empty;
83 }
84
85 string hashed = Util.Md5Hash(password + ":" +
86 data.Data["passwordSalt"].ToString());
87
88 m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString());
62 89
63 if (data != null && data.Data != null) 90 if (data.Data["passwordHash"].ToString() == hashed)
64 { 91 {
65 if (!data.Data.ContainsKey("passwordHash") || 92 return GetToken(principalID, lifetime);
93 }
94
95 if (user == null)
96 {
97 m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID);
98 return String.Empty;
99 }
100
101 int impersonateFlag = 1 << 6;
102
103 if ((user.UserFlags & impersonateFlag) == 0)
104 return String.Empty;
105
106 List<UserAccount> accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200");
107 if (accounts == null || accounts.Count == 0)
108 return String.Empty;
109
110 foreach (UserAccount a in accounts)
111 {
112 data = m_Database.Get(a.PrincipalID);
113 if (data == null || data.Data == null ||
114 !data.Data.ContainsKey("passwordHash") ||
66 !data.Data.ContainsKey("passwordSalt")) 115 !data.Data.ContainsKey("passwordSalt"))
67 { 116 {
68 return String.Empty; 117 continue;
69 } 118 }
70 119
71 string hashed = Util.Md5Hash(password + ":" + 120 hashed = Util.Md5Hash(password + ":" +
72 data.Data["passwordSalt"].ToString()); 121 data.Data["passwordSalt"].ToString());
73 122
74 m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString());
75
76 if (data.Data["passwordHash"].ToString() == hashed) 123 if (data.Data["passwordHash"].ToString() == hashed)
77 { 124 {
125 m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID);
78 return GetToken(principalID, lifetime); 126 return GetToken(principalID, lifetime);
79 } 127 }
80 } 128 }
81 129
82 m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID); 130 m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID);
83 return String.Empty; 131 return String.Empty;
84 } 132 }
85 } 133 }
diff --git a/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs b/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs
index d1a5b0f..6d9aae3 100644
--- a/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs
+++ b/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs
@@ -47,6 +47,11 @@ namespace OpenSim.Services.AuthenticationService
47// LogManager.GetLogger( 47// LogManager.GetLogger(
48// MethodBase.GetCurrentMethod().DeclaringType); 48// MethodBase.GetCurrentMethod().DeclaringType);
49 49
50 public WebkeyAuthenticationService(IConfigSource config, IUserAccountService userService) :
51 base(config, userService)
52 {
53 }
54
50 public WebkeyAuthenticationService(IConfigSource config) : 55 public WebkeyAuthenticationService(IConfigSource config) :
51 base(config) 56 base(config)
52 { 57 {
diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs
index 65b3537..ad18a23 100644
--- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs
@@ -30,6 +30,7 @@ using System;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO; 31using System.IO;
32using System.Reflection; 32using System.Reflection;
33using System.Timers;
33using Nini.Config; 34using Nini.Config;
34using OpenSim.Framework; 35using OpenSim.Framework;
35using OpenSim.Framework.Console; 36using OpenSim.Framework.Console;
@@ -48,7 +49,9 @@ namespace OpenSim.Services.Connectors
48 49
49 private string m_ServerURI = String.Empty; 50 private string m_ServerURI = String.Empty;
50 private IImprovedAssetCache m_Cache = null; 51 private IImprovedAssetCache m_Cache = null;
51 52 private int m_retryCounter;
53 private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>();
54 private Timer m_retryTimer;
52 public AssetServicesConnector() 55 public AssetServicesConnector()
53 { 56 {
54 } 57 }
@@ -85,6 +88,55 @@ namespace OpenSim.Services.Connectors
85 MainConsole.Instance.Commands.AddCommand("asset", false, "dump asset", 88 MainConsole.Instance.Commands.AddCommand("asset", false, "dump asset",
86 "dump asset <id> <file>", 89 "dump asset <id> <file>",
87 "dump one cached asset", HandleDumpAsset); 90 "dump one cached asset", HandleDumpAsset);
91
92 m_retryTimer = new Timer();
93 m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck);
94 m_retryTimer.Interval = 60000;
95 }
96
97 protected void retryCheck(object source, ElapsedEventArgs e)
98 {
99 m_retryCounter++;
100 if (m_retryCounter > 60) m_retryCounter -= 60;
101 List<int> keys = new List<int>();
102 foreach (int a in m_retryQueue.Keys)
103 {
104 keys.Add(a);
105 }
106 foreach (int a in keys)
107 {
108 //We exponentially fall back on frequency until we reach one attempt per hour
109 //The net result is that we end up in the queue for roughly 24 hours..
110 //24 hours worth of assets could be a lot, so the hope is that the region admin
111 //will have gotten the asset connector back online quickly!
112
113 int timefactor = a ^ 2;
114 if (timefactor > 60)
115 {
116 timefactor = 60;
117 }
118
119 //First, find out if we care about this timefactor
120 if (timefactor % a == 0)
121 {
122 //Yes, we do!
123 List<AssetBase> retrylist = m_retryQueue[a];
124 m_retryQueue.Remove(a);
125
126 foreach(AssetBase ass in retrylist)
127 {
128 Store(ass); //Store my ass. This function will put it back in the dictionary if it fails
129 }
130 }
131 }
132
133 if (m_retryQueue.Count == 0)
134 {
135 //It might only be one tick per minute, but I have
136 //repented and abandoned my wasteful ways
137 m_retryCounter = 0;
138 m_retryTimer.Stop();
139 }
88 } 140 }
89 141
90 protected void SetCache(IImprovedAssetCache cache) 142 protected void SetCache(IImprovedAssetCache cache)
@@ -99,8 +151,8 @@ namespace OpenSim.Services.Connectors
99 AssetBase asset = null; 151 AssetBase asset = null;
100 if (m_Cache != null) 152 if (m_Cache != null)
101 asset = m_Cache.Get(id); 153 asset = m_Cache.Get(id);
102 154
103 if (asset == null) 155 if (asset == null || asset.Data == null || asset.Data.Length == 0)
104 { 156 {
105 asset = SynchronousRestObjectRequester. 157 asset = SynchronousRestObjectRequester.
106 MakeRequest<int, AssetBase>("GET", uri, 0); 158 MakeRequest<int, AssetBase>("GET", uri, 0);
@@ -177,7 +229,7 @@ namespace OpenSim.Services.Connectors
177 if (m_Cache != null) 229 if (m_Cache != null)
178 asset = m_Cache.Get(id); 230 asset = m_Cache.Get(id);
179 231
180 if (asset == null) 232 if (asset == null || asset.Data == null || asset.Data.Length == 0)
181 { 233 {
182 bool result = false; 234 bool result = false;
183 235
@@ -204,11 +256,10 @@ namespace OpenSim.Services.Connectors
204 256
205 public string Store(AssetBase asset) 257 public string Store(AssetBase asset)
206 { 258 {
259 if (m_Cache != null)
260 m_Cache.Cache(asset);
207 if (asset.Temporary || asset.Local) 261 if (asset.Temporary || asset.Local)
208 { 262 {
209 if (m_Cache != null)
210 m_Cache.Cache(asset);
211
212 return asset.ID; 263 return asset.ID;
213 } 264 }
214 265
@@ -218,24 +269,57 @@ namespace OpenSim.Services.Connectors
218 try 269 try
219 { 270 {
220 newID = SynchronousRestObjectRequester. 271 newID = SynchronousRestObjectRequester.
221 MakeRequest<AssetBase, string>("POST", uri, asset); 272 MakeRequest<AssetBase, string>("POST", uri, asset, 25);
273 if (newID == null || newID == "")
274 {
275 newID = UUID.Zero.ToString();
276 }
222 } 277 }
223 catch (Exception e) 278 catch (Exception e)
224 { 279 {
225 m_log.WarnFormat("[ASSET CONNECTOR]: Unable to send asset {0} to asset server. Reason: {1}", asset.ID, e.Message); 280 newID = UUID.Zero.ToString();
226 } 281 }
227 282
228 if (newID != String.Empty) 283 if (newID == UUID.Zero.ToString())
229 { 284 {
230 // Placing this here, so that this work with old asset servers that don't send any reply back 285 //The asset upload failed, put it in a queue for later
231 // SynchronousRestObjectRequester returns somethins that is not an empty string 286 asset.UploadAttempts++;
232 if (newID != null) 287 if (asset.UploadAttempts > 30)
233 asset.ID = newID; 288 {
234 289 //By this stage we've been in the queue for a good few hours;
235 if (m_Cache != null) 290 //We're going to drop the asset.
236 m_Cache.Cache(asset); 291 m_log.ErrorFormat("[Assets] Dropping asset {0} - Upload has been in the queue for too long.", asset.ID.ToString());
292 }
293 else
294 {
295 if (!m_retryQueue.ContainsKey(asset.UploadAttempts))
296 {
297 m_retryQueue.Add(asset.UploadAttempts, new List<AssetBase>());
298 }
299 List<AssetBase> m_queue = m_retryQueue[asset.UploadAttempts];
300 m_queue.Add(asset);
301 m_log.WarnFormat("[Assets] Upload failed: {0} - Requeuing asset for another run.", asset.ID.ToString());
302 m_retryTimer.Start();
303 }
304 }
305 else
306 {
307 if (asset.UploadAttempts > 0)
308 {
309 m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), asset.UploadAttempts.ToString());
310 }
311 if (newID != String.Empty)
312 {
313 // Placing this here, so that this work with old asset servers that don't send any reply back
314 // SynchronousRestObjectRequester returns somethins that is not an empty string
315 if (newID != null)
316 asset.ID = newID;
317
318 if (m_Cache != null)
319 m_Cache.Cache(asset);
320 }
237 } 321 }
238 return newID; 322 return asset.ID;
239 } 323 }
240 324
241 public bool UpdateContent(string id, byte[] data) 325 public bool UpdateContent(string id, byte[] data)
diff --git a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs
index 252f7a1..ba39c99 100644
--- a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs
@@ -131,4 +131,4 @@ namespace OpenSim.Services.Connectors
131 return landData; 131 return landData;
132 } 132 }
133 } 133 }
134} \ No newline at end of file 134}
diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
index 41ebeaf..f1c99ce 100644
--- a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
@@ -300,6 +300,17 @@ namespace OpenSim.Services.Connectors
300 { 300 {
301 pinfo = new PresenceInfo((Dictionary<string, object>)replyData["result"]); 301 pinfo = new PresenceInfo((Dictionary<string, object>)replyData["result"]);
302 } 302 }
303 else
304 {
305 if (replyData["result"].ToString() == "null")
306 return null;
307
308 m_log.DebugFormat("[PRESENCE CONNECTOR]: Invalid reply (result not dictionary) received from presence server when querying for sessionID {0}", sessionID.ToString());
309 }
310 }
311 else
312 {
313 m_log.DebugFormat("[PRESENCE CONNECTOR]: Invalid reply received from presence server when querying for sessionID {0}", sessionID.ToString());
303 } 314 }
304 315
305 return pinfo; 316 return pinfo;
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
index 9c72a61..daf94fe 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -102,6 +102,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
102 102
103 public string RegisterRegion(UUID scopeID, GridRegion regionInfo) 103 public string RegisterRegion(UUID scopeID, GridRegion regionInfo)
104 { 104 {
105 IPEndPoint ext = regionInfo.ExternalEndPoint;
106 if (ext == null) return "Region registration for " + regionInfo.RegionName + " failed: Could not resolve EndPoint";
105 // Generate and upload our map tile in PNG format to the SimianGrid AddMapTile service 107 // Generate and upload our map tile in PNG format to the SimianGrid AddMapTile service
106// Scene scene; 108// Scene scene;
107// if (m_scenes.TryGetValue(regionInfo.RegionID, out scene)) 109// if (m_scenes.TryGetValue(regionInfo.RegionID, out scene))
@@ -117,7 +119,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
117 { "ServerURI", OSD.FromString(regionInfo.ServerURI) }, 119 { "ServerURI", OSD.FromString(regionInfo.ServerURI) },
118 { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) }, 120 { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) },
119 { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) }, 121 { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) },
120 { "ExternalAddress", OSD.FromString(regionInfo.ExternalEndPoint.Address.ToString()) }, 122 { "ExternalAddress", OSD.FromString(ext.Address.ToString()) },
121 { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) }, 123 { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) },
122 { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) }, 124 { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) },
123 { "Access", OSD.FromInteger(regionInfo.Access) }, 125 { "Access", OSD.FromInteger(regionInfo.Access) },
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
index 9c150ee..394c2b7 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
@@ -191,6 +191,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
191 return accounts; 191 return accounts;
192 } 192 }
193 193
194 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query)
195 {
196 return null;
197 }
198
194 public bool StoreUserAccount(UserAccount data) 199 public bool StoreUserAccount(UserAccount data)
195 { 200 {
196 m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account for " + data.Name); 201 m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account for " + data.Name);
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
index f34c2bd..fbfc2dd 100644
--- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
@@ -247,9 +247,7 @@ namespace OpenSim.Services.Connectors.Simulation
247 return true; 247 return true;
248 } 248 }
249 249
250 /// <summary> 250 private bool CloseAgent(GridRegion destination, UUID id, bool ChildOnly)
251 /// </summary>
252 public bool CloseAgent(GridRegion destination, UUID id)
253 { 251 {
254 // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent start"); 252 // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent start");
255 253
@@ -267,6 +265,16 @@ namespace OpenSim.Services.Connectors.Simulation
267 return true; 265 return true;
268 } 266 }
269 267
268 public bool CloseChildAgent(GridRegion destination, UUID id)
269 {
270 return CloseAgent(destination, id, true);
271 }
272
273 public bool CloseAgent(GridRegion destination, UUID id)
274 {
275 return CloseAgent(destination, id, false);
276 }
277
270 #endregion Agents 278 #endregion Agents
271 279
272 #region Objects 280 #region Objects
diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs
index 2a5df83..205a4aa 100644
--- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs
+++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs
@@ -187,6 +187,11 @@ namespace OpenSim.Services.Connectors
187 return accounts; 187 return accounts;
188 } 188 }
189 189
190 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where)
191 {
192 return null; // Not implemented for regions
193 }
194
190 public virtual bool StoreUserAccount(UserAccount data) 195 public virtual bool StoreUserAccount(UserAccount data)
191 { 196 {
192 Dictionary<string, object> sendData = new Dictionary<string, object>(); 197 Dictionary<string, object> sendData = new Dictionary<string, object>();
diff --git a/OpenSim/Services/HypergridService/UserAccountCache.cs b/OpenSim/Services/HypergridService/UserAccountCache.cs
index 3e9aea1..c431060 100644
--- a/OpenSim/Services/HypergridService/UserAccountCache.cs
+++ b/OpenSim/Services/HypergridService/UserAccountCache.cs
@@ -89,6 +89,11 @@ namespace OpenSim.Services.HypergridService
89 return null; 89 return null;
90 } 90 }
91 91
92 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query)
93 {
94 return null;
95 }
96
92 public List<UserAccount> GetUserAccounts(UUID scopeID, string query) 97 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
93 { 98 {
94 return null; 99 return null;
diff --git a/OpenSim/Services/Interfaces/IAttachmentsService.cs b/OpenSim/Services/Interfaces/IAttachmentsService.cs
new file mode 100644
index 0000000..bdde369
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IAttachmentsService.cs
@@ -0,0 +1,17 @@
1////////////////////////////////////////////////////////////////
2//
3// (c) 2009, 2010 Careminster Limited and Melanie Thielker
4//
5// All rights reserved
6//
7using System;
8using Nini.Config;
9
10namespace OpenSim.Services.Interfaces
11{
12 public interface IAttachmentsService
13 {
14 string Get(string id);
15 void Store(string id, string data);
16 }
17}
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs
index a34f0be..f569fc8 100644
--- a/OpenSim/Services/Interfaces/IGridService.cs
+++ b/OpenSim/Services/Interfaces/IGridService.cs
@@ -300,9 +300,13 @@ namespace OpenSim.Services.Interfaces
300 } 300 }
301 catch (SocketException e) 301 catch (SocketException e)
302 { 302 {
303 throw new Exception( 303 /*throw new Exception(
304 "Unable to resolve local hostname " + m_externalHostName + " innerException of type '" + 304 "Unable to resolve local hostname " + m_externalHostName + " innerException of type '" +
305 e + "' attached to this exception", e); 305 e + "' attached to this exception", e);*/
306 // Don't throw a fatal exception here, instead, return Null and handle it in the caller.
307 // Reason is, on systems such as OSgrid it has occured that known hostnames stop
308 // resolving and thus make surrounding regions crash out with this exception.
309 return null;
306 } 310 }
307 311
308 return new IPEndPoint(ia, m_internalEndPoint.Port); 312 return new IPEndPoint(ia, m_internalEndPoint.Port);
@@ -360,6 +364,12 @@ namespace OpenSim.Services.Interfaces
360 if (kvp.ContainsKey("regionName")) 364 if (kvp.ContainsKey("regionName"))
361 RegionName = (string)kvp["regionName"]; 365 RegionName = (string)kvp["regionName"];
362 366
367 if (kvp.ContainsKey("access"))
368 {
369 byte access = Convert.ToByte((string)kvp["access"]);
370 Maturity = (int)Util.ConvertAccessLevelToMaturity(access);
371 }
372
363 if (kvp.ContainsKey("serverIP")) 373 if (kvp.ContainsKey("serverIP"))
364 { 374 {
365 //int port = 0; 375 //int port = 0;
diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs
index 12e8982..1f8474c 100644
--- a/OpenSim/Services/Interfaces/ISimulationService.cs
+++ b/OpenSim/Services/Interfaces/ISimulationService.cs
@@ -73,6 +73,14 @@ namespace OpenSim.Services.Interfaces
73 bool ReleaseAgent(UUID originRegion, UUID id, string uri); 73 bool ReleaseAgent(UUID originRegion, UUID id, string uri);
74 74
75 /// <summary> 75 /// <summary>
76 /// Close child agent.
77 /// </summary>
78 /// <param name="regionHandle"></param>
79 /// <param name="id"></param>
80 /// <returns></returns>
81 bool CloseChildAgent(GridRegion destination, UUID id);
82
83 /// <summary>
76 /// Close agent. 84 /// Close agent.
77 /// </summary> 85 /// </summary>
78 /// <param name="regionHandle"></param> 86 /// <param name="regionHandle"></param>
diff --git a/OpenSim/Services/Interfaces/IUserAccountService.cs b/OpenSim/Services/Interfaces/IUserAccountService.cs
index 9c992e0..80258d6 100644
--- a/OpenSim/Services/Interfaces/IUserAccountService.cs
+++ b/OpenSim/Services/Interfaces/IUserAccountService.cs
@@ -150,6 +150,7 @@ namespace OpenSim.Services.Interfaces
150 /// <param name="query"></param> 150 /// <param name="query"></param>
151 /// <returns></returns> 151 /// <returns></returns>
152 List<UserAccount> GetUserAccounts(UUID scopeID, string query); 152 List<UserAccount> GetUserAccounts(UUID scopeID, string query);
153 List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where);
153 154
154 /// <summary> 155 /// <summary>
155 /// Store the data given, wich replaces the stored data, therefore must be complete. 156 /// Store the data given, wich replaces the stored data, therefore must be complete.
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
index f985ab2..e98cc22 100644
--- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
@@ -56,6 +56,7 @@ namespace OpenSim.Services.LLLoginService
56 public static LLFailedLoginResponse InventoryProblem; 56 public static LLFailedLoginResponse InventoryProblem;
57 public static LLFailedLoginResponse DeadRegionProblem; 57 public static LLFailedLoginResponse DeadRegionProblem;
58 public static LLFailedLoginResponse LoginBlockedProblem; 58 public static LLFailedLoginResponse LoginBlockedProblem;
59 public static LLFailedLoginResponse UnverifiedAccountProblem;
59 public static LLFailedLoginResponse AlreadyLoggedInProblem; 60 public static LLFailedLoginResponse AlreadyLoggedInProblem;
60 public static LLFailedLoginResponse InternalError; 61 public static LLFailedLoginResponse InternalError;
61 62
@@ -76,6 +77,10 @@ namespace OpenSim.Services.LLLoginService
76 LoginBlockedProblem = new LLFailedLoginResponse("presence", 77 LoginBlockedProblem = new LLFailedLoginResponse("presence",
77 "Logins are currently restricted. Please try again later.", 78 "Logins are currently restricted. Please try again later.",
78 "false"); 79 "false");
80 UnverifiedAccountProblem = new LLFailedLoginResponse("presence",
81 "Your account has not yet been verified. Please check " +
82 "your email and click the provided link.",
83 "false");
79 AlreadyLoggedInProblem = new LLFailedLoginResponse("presence", 84 AlreadyLoggedInProblem = new LLFailedLoginResponse("presence",
80 "You appear to be already logged in. " + 85 "You appear to be already logged in. " +
81 "If this is not the case please wait for your session to timeout. " + 86 "If this is not the case please wait for your session to timeout. " +
@@ -325,6 +330,7 @@ namespace OpenSim.Services.LLLoginService
325 private void FillOutRegionData(GridRegion destination) 330 private void FillOutRegionData(GridRegion destination)
326 { 331 {
327 IPEndPoint endPoint = destination.ExternalEndPoint; 332 IPEndPoint endPoint = destination.ExternalEndPoint;
333 if (endPoint == null) return;
328 SimAddress = endPoint.Address.ToString(); 334 SimAddress = endPoint.Address.ToString();
329 SimPort = (uint)endPoint.Port; 335 SimPort = (uint)endPoint.Port;
330 RegionX = (uint)destination.RegionLocX; 336 RegionX = (uint)destination.RegionLocX;
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index 281b6e3..93e4a8f 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -113,7 +113,8 @@ namespace OpenSim.Services.LLLoginService
113 Object[] args = new Object[] { config }; 113 Object[] args = new Object[] { config };
114 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); 114 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
115 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); 115 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
116 m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args); 116 Object[] authArgs = new Object[] { config, m_UserAccountService };
117 m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, authArgs);
117 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args); 118 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args);
118 119
119 if (gridService != string.Empty) 120 if (gridService != string.Empty)
@@ -229,6 +230,12 @@ namespace OpenSim.Services.LLLoginService
229 return LLFailedLoginResponse.UserProblem; 230 return LLFailedLoginResponse.UserProblem;
230 } 231 }
231 232
233 if (account.UserLevel < 0)
234 {
235 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: Unverified account");
236 return LLFailedLoginResponse.UnverifiedAccountProblem;
237 }
238
232 if (account.UserLevel < m_MinLoginLevel) 239 if (account.UserLevel < m_MinLoginLevel)
233 { 240 {
234 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: login is blocked for user level {0}", account.UserLevel); 241 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: login is blocked for user level {0}", account.UserLevel);
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs
index f376cf8..de6d32c 100644
--- a/OpenSim/Services/UserAccountService/UserAccountService.cs
+++ b/OpenSim/Services/UserAccountService/UserAccountService.cs
@@ -282,6 +282,21 @@ namespace OpenSim.Services.UserAccountService
282 return ret; 282 return ret;
283 } 283 }
284 284
285 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where)
286 {
287 UserAccountData[] d = m_Database.GetUsersWhere(scopeID, where);
288
289 if (d == null)
290 return new List<UserAccount>();
291
292 List<UserAccount> ret = new List<UserAccount>();
293
294 foreach (UserAccountData data in d)
295 ret.Add(MakeUserAccount(data));
296
297 return ret;
298 }
299
285 #endregion 300 #endregion
286 301
287 #region Console commands 302 #region Console commands
diff --git a/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs
index 4a15cf2..5bab62c 100644
--- a/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs
+++ b/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs
@@ -54,9 +54,10 @@ namespace OpenSim.Tests.Common.Mock
54 return assets.Find(x=>x.FullID == uuid); 54 return assets.Find(x=>x.FullID == uuid);
55 } 55 }
56 56
57 public void StoreAsset(AssetBase asset) 57 public bool StoreAsset(AssetBase asset)
58 { 58 {
59 assets.Add(asset); 59 assets.Add(asset);
60 return true;
60 } 61 }
61 62
62 public List<AssetMetadata> FetchAssetMetadataSet(int start, int count) { return new List<AssetMetadata>(count); } 63 public List<AssetMetadata> FetchAssetMetadataSet(int start, int count) { return new List<AssetMetadata>(count); }
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index dc0d4de..147571b 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Tests.Common.Mock
65 public event MoneyTransferRequest OnMoneyTransferRequest; 65 public event MoneyTransferRequest OnMoneyTransferRequest;
66 public event ParcelBuy OnParcelBuy; 66 public event ParcelBuy OnParcelBuy;
67 public event Action<IClientAPI> OnConnectionClosed; 67 public event Action<IClientAPI> OnConnectionClosed;
68 68 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
69 public event ImprovedInstantMessage OnInstantMessage; 69 public event ImprovedInstantMessage OnInstantMessage;
70 public event ChatMessage OnChatFromClient; 70 public event ChatMessage OnChatFromClient;
71 public event TextureRequest OnRequestTexture; 71 public event TextureRequest OnRequestTexture;
@@ -487,7 +487,7 @@ namespace OpenSim.Tests.Common.Mock
487 487
488 } 488 }
489 489
490 public virtual void SendKillObject(ulong regionHandle, uint localID) 490 public virtual void SendKillObject(ulong regionHandle, List<uint> localID)
491 { 491 {
492 } 492 }
493 493
@@ -890,6 +890,10 @@ namespace OpenSim.Tests.Common.Mock
890 890
891 public void Close() 891 public void Close()
892 { 892 {
893 Close(true);
894 }
895 public void Close(bool sendStop)
896 {
893 m_scene.RemoveClient(AgentId); 897 m_scene.RemoveClient(AgentId);
894 } 898 }
895 899