aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs91
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs30
-rw-r--r--OpenSim/ApplicationPlugins/Rest/RestPlugin.cs14
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs18
-rw-r--r--OpenSim/Data/IRegionData.cs15
-rw-r--r--OpenSim/Data/IXInventoryData.cs10
-rw-r--r--OpenSim/Data/MSSQL/MSSQLRegionData.cs1
-rw-r--r--OpenSim/Data/MySQL/MySQLRegionData.cs4
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs457
-rw-r--r--OpenSim/Data/MySQL/Resources/GridUserStore.migrations5
-rw-r--r--OpenSim/Data/Null/NullRegionData.cs1
-rw-r--r--OpenSim/Framework/AssetPermissions.cs84
-rw-r--r--OpenSim/Framework/Cache.cs83
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs114
-rw-r--r--OpenSim/Framework/Constants.cs1
-rw-r--r--OpenSim/Framework/EstateSettings.cs10
-rw-r--r--OpenSim/Framework/GridInstantMessage.cs9
-rw-r--r--OpenSim/Framework/IClientAPI.cs15
-rw-r--r--OpenSim/Framework/InventoryFolderBase.cs18
-rw-r--r--OpenSim/Framework/Monitoring/BaseStatsCollector.cs23
-rw-r--r--OpenSim/Framework/Monitoring/MemoryWatchdog.cs10
-rw-r--r--OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs19
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs309
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs35
-rw-r--r--OpenSim/Framework/Pool.cs (renamed from OpenSim/Region/CoreModules/Framework/InventoryAccess/HGUuidGatherer.cs)55
-rw-r--r--OpenSim/Framework/RegionFlags.cs53
-rw-r--r--OpenSim/Framework/RegionInfo.cs72
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs5
-rw-r--r--OpenSim/Framework/Serialization/External/OspResolver.cs14
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs32
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs272
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs22
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs148
-rw-r--r--OpenSim/Framework/Servers/VersionInfo.cs2
-rw-r--r--OpenSim/Framework/Util.cs51
-rw-r--r--OpenSim/Framework/WebUtil.cs81
-rw-r--r--OpenSim/Region/Application/OpenSim.cs72
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs72
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs55
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs211
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs (renamed from OpenSim/Framework/PacketPool.cs)59
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs7
-rw-r--r--OpenSim/Region/ClientStack/RegionApplicationBase.cs2
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs138
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs222
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs39
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs30
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs76
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs64
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs42
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs51
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs220
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs79
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs4
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs331
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs61
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs277
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs17
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs49
-rw-r--r--OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs (renamed from OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs)81
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs281
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs159
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs23
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs7
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs136
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs10
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs19
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/RemoteGridUserServiceConnector.cs46
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs434
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs176
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs634
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs153
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs438
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs232
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs404
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs260
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs61
-rw-r--r--OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs7
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs69
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEstateModule.cs4
-rw-r--r--OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs71
-rw-r--r--OpenSim/Region/Framework/Interfaces/IUrlModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IUserManagement.cs29
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs521
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs618
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs106
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs119
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs32
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs33
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs36
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs136
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs18
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs14
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs2
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs8
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs58
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs549
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs43
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs618
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs112
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs445
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs218
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1157
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs774
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs756
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs492
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs716
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs4
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs37
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs56
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs3
-rw-r--r--OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml14
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs1401
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs8
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs24
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs341
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs115
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs53
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs46
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Helpers.cs28
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs77
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs134
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/EventManager.cs29
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs57
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs56
-rw-r--r--OpenSim/Server/Base/ServicesServerBase.cs41
-rw-r--r--OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs18
-rw-r--r--OpenSim/Server/ServerMain.cs22
-rw-r--r--OpenSim/Services/AssetService/AssetServiceBase.cs4
-rw-r--r--OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs8
-rw-r--r--OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs2
-rw-r--r--OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs9
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs8
-rw-r--r--OpenSim/Services/GridService/GridService.cs99
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs6
-rw-r--r--OpenSim/Services/HypergridService/GatekeeperService.cs93
-rw-r--r--OpenSim/Services/HypergridService/HGAssetService.cs26
-rw-r--r--OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs61
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs103
-rw-r--r--OpenSim/Services/Interfaces/IGridService.cs13
-rw-r--r--OpenSim/Services/Interfaces/IGridUserService.cs3
-rw-r--r--OpenSim/Services/InventoryService/XInventoryService.cs65
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs2
-rw-r--r--OpenSim/Services/UserAccountService/GridUserService.cs13
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs2
-rw-r--r--OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs4
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs6
-rw-r--r--OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs131
-rw-r--r--OpenSim/Tests/Common/TestHelpers.cs1
-rw-r--r--OpenSim/Tests/Performance/NPCPerformanceTests.cs (renamed from OpenSim/Tests/Torture/NPCTortureTests.cs)6
-rw-r--r--OpenSim/Tests/Performance/ObjectPerformanceTests.cs (renamed from OpenSim/Tests/Torture/ObjectTortureTests.cs)6
-rw-r--r--OpenSim/Tests/Performance/ScriptPerformanceTests.cs (renamed from OpenSim/Tests/Torture/ScriptTortureTests.cs)6
-rw-r--r--OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs132
192 files changed, 13715 insertions, 5605 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index 437d150..9c933ee 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -696,7 +696,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
696 696
697 region.ExternalHostName = (string) requestData["external_address"]; 697 region.ExternalHostName = (string) requestData["external_address"];
698 698
699 bool persist = Convert.ToBoolean((string) requestData["persist"]); 699 bool persist = Convert.ToBoolean(requestData["persist"]);
700 if (persist) 700 if (persist)
701 { 701 {
702 // default place for region configuration files is in the 702 // default place for region configuration files is in the
@@ -852,7 +852,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
852 responseData["success"] = true; 852 responseData["success"] = true;
853 responseData["region_name"] = region.RegionName; 853 responseData["region_name"] = region.RegionName;
854 responseData["region_id"] = region.RegionID.ToString(); 854 responseData["region_id"] = region.RegionID.ToString();
855 responseData["region_uuid"] = region.RegionID.ToString(); //Deprecate July 2012
856 855
857 m_log.Info("[RADMIN]: CreateRegion: request complete"); 856 m_log.Info("[RADMIN]: CreateRegion: request complete");
858 } 857 }
@@ -1106,8 +1105,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1106 string lastName = (string) requestData["user_lastname"]; 1105 string lastName = (string) requestData["user_lastname"];
1107 string password = (string) requestData["user_password"]; 1106 string password = (string) requestData["user_password"];
1108 1107
1109 uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); 1108 uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
1110 uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); 1109 uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
1111 1110
1112 string email = ""; // empty string for email 1111 string email = ""; // empty string for email
1113 if (requestData.Contains("user_email")) 1112 if (requestData.Contains("user_email"))
@@ -1304,9 +1303,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1304 1303
1305 if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"]; 1304 if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
1306 if (requestData.ContainsKey("start_region_x")) 1305 if (requestData.ContainsKey("start_region_x"))
1307 regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); 1306 regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
1308 if (requestData.ContainsKey("start_region_y")) 1307 if (requestData.ContainsKey("start_region_y"))
1309 regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); 1308 regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
1310 1309
1311 // if (requestData.ContainsKey("start_lookat_x")) 1310 // if (requestData.ContainsKey("start_lookat_x"))
1312 // ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]); 1311 // ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@@ -1493,6 +1492,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1493 /// <description>profile url</description></item> 1492 /// <description>profile url</description></item>
1494 /// <item><term>noassets</term> 1493 /// <item><term>noassets</term>
1495 /// <description>true if no assets should be saved</description></item> 1494 /// <description>true if no assets should be saved</description></item>
1495 /// <item><term>all</term>
1496 /// <description>true to save all the regions in the simulator</description></item>
1496 /// <item><term>perm</term> 1497 /// <item><term>perm</term>
1497 /// <description>C and/or T</description></item> 1498 /// <description>C and/or T</description></item>
1498 /// </list> 1499 /// </list>
@@ -1549,6 +1550,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1549 options["checkPermissions"] = (string)requestData["perm"]; 1550 options["checkPermissions"] = (string)requestData["perm"];
1550 } 1551 }
1551 1552
1553 if ((string)requestData["all"] == "true")
1554 {
1555 options["all"] = (string)requestData["all"];
1556 }
1557
1552 IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>(); 1558 IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
1553 1559
1554 if (archiver != null) 1560 if (archiver != null)
@@ -2008,29 +2014,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
2008 { 2014 {
2009 return; 2015 return;
2010 } 2016 }
2011 #region Deprecate July 2012
2012 //region_ID, regionid, region_uuid will be deprecated in July 2012!!!!!!
2013 else if (requestData.ContainsKey("regionid") &&
2014 !String.IsNullOrEmpty((string)requestData["regionid"]))
2015 {
2016 m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
2017 }
2018 else if (requestData.ContainsKey("region_ID") &&
2019 !String.IsNullOrEmpty((string)requestData["region_ID"]))
2020 {
2021 m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
2022 }
2023 else if (requestData.ContainsKey("regionID") &&
2024 !String.IsNullOrEmpty((string)requestData["regionID"]))
2025 {
2026 m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
2027 }
2028 else if (requestData.ContainsKey("region_uuid") &&
2029 !String.IsNullOrEmpty((string)requestData["region_uuid"]))
2030 {
2031 m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
2032 }
2033 #endregion
2034 else 2017 else
2035 { 2018 {
2036 responseData["accepted"] = false; 2019 responseData["accepted"] = false;
@@ -2052,56 +2035,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
2052 throw new Exception(String.Format("Region ID {0} not found", regionID)); 2035 throw new Exception(String.Format("Region ID {0} not found", regionID));
2053 } 2036 }
2054 } 2037 }
2055 #region Deprecate July 2012
2056 else if (requestData.ContainsKey("regionid") &&
2057 !String.IsNullOrEmpty((string)requestData["regionid"]))
2058 {
2059 m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
2060
2061 UUID regionID = (UUID)(string)requestData["regionid"];
2062 if (!m_application.SceneManager.TryGetScene(regionID, out scene))
2063 {
2064 responseData["error"] = String.Format("Region ID {0} not found", regionID);
2065 throw new Exception(String.Format("Region ID {0} not found", regionID));
2066 }
2067 }
2068 else if (requestData.ContainsKey("region_ID") &&
2069 !String.IsNullOrEmpty((string)requestData["region_ID"]))
2070 {
2071 m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
2072
2073 UUID regionID = (UUID)(string)requestData["region_ID"];
2074 if (!m_application.SceneManager.TryGetScene(regionID, out scene))
2075 {
2076 responseData["error"] = String.Format("Region ID {0} not found", regionID);
2077 throw new Exception(String.Format("Region ID {0} not found", regionID));
2078 }
2079 }
2080 else if (requestData.ContainsKey("regionID") &&
2081 !String.IsNullOrEmpty((string)requestData["regionID"]))
2082 {
2083 m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
2084
2085 UUID regionID = (UUID)(string)requestData["regionID"];
2086 if (!m_application.SceneManager.TryGetScene(regionID, out scene))
2087 {
2088 responseData["error"] = String.Format("Region ID {0} not found", regionID);
2089 throw new Exception(String.Format("Region ID {0} not found", regionID));
2090 }
2091 }
2092 else if (requestData.ContainsKey("region_uuid") &&
2093 !String.IsNullOrEmpty((string)requestData["region_uuid"]))
2094 {
2095 m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
2096
2097 UUID regionID = (UUID)(string)requestData["region_uuid"];
2098 if (!m_application.SceneManager.TryGetScene(regionID, out scene))
2099 {
2100 responseData["error"] = String.Format("Region ID {0} not found", regionID);
2101 throw new Exception(String.Format("Region ID {0} not found", regionID));
2102 }
2103 }
2104 #endregion
2105 else if (requestData.ContainsKey("region_name") && 2038 else if (requestData.ContainsKey("region_name") &&
2106 !String.IsNullOrEmpty((string)requestData["region_name"])) 2039 !String.IsNullOrEmpty((string)requestData["region_name"]))
2107 { 2040 {
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
index cb88695..072bd6f 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
@@ -312,14 +312,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
312 // Now that everything is setup we can proceed to 312 // Now that everything is setup we can proceed to
313 // add THIS agent to the HTTP server's handler list 313 // add THIS agent to the HTTP server's handler list
314 314
315 if (!AddAgentHandler(Rest.Name,this)) 315 // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
316 { 316 // have to be handled through the AddHttpHandler interface.
317 Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); 317// if (!AddAgentHandler(Rest.Name,this))
318 foreach (IRest handler in handlers) 318// {
319 { 319// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
320 handler.Close(); 320// foreach (IRest handler in handlers)
321 } 321// {
322 } 322// handler.Close();
323// }
324// }
323 325
324 } 326 }
325 catch (Exception e) 327 catch (Exception e)
@@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
342 { 344 {
343 Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); 345 Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
344 346
345 try 347 // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
346 { 348 // have to be handled through the AddHttpHandler interface.
347 RemoveAgentHandler(Rest.Name, this); 349// try
348 } 350// {
349 catch (KeyNotFoundException){} 351// RemoveAgentHandler(Rest.Name, this);
352// }
353// catch (KeyNotFoundException){}
350 354
351 foreach (IRest handler in handlers) 355 foreach (IRest handler in handlers)
352 { 356 {
diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
index eb16750..a2425b5 100644
--- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
+++ b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
@@ -297,7 +297,9 @@ namespace OpenSim.ApplicationPlugins.Rest
297 { 297 {
298 if (!IsEnabled) return false; 298 if (!IsEnabled) return false;
299 _agents.Add(agentName, handler); 299 _agents.Add(agentName, handler);
300 return _httpd.AddAgentHandler(agentName, handler); 300// return _httpd.AddAgentHandler(agentName, handler);
301
302 return false;
301 } 303 }
302 304
303 /// <summary> 305 /// <summary>
@@ -316,7 +318,7 @@ namespace OpenSim.ApplicationPlugins.Rest
316 if (_agents[agentName] == handler) 318 if (_agents[agentName] == handler)
317 { 319 {
318 _agents.Remove(agentName); 320 _agents.Remove(agentName);
319 return _httpd.RemoveAgentHandler(agentName, handler); 321// return _httpd.RemoveAgentHandler(agentName, handler);
320 } 322 }
321 return false; 323 return false;
322 } 324 }
@@ -358,10 +360,10 @@ namespace OpenSim.ApplicationPlugins.Rest
358 _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); 360 _httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
359 } 361 }
360 _handlers = null; 362 _handlers = null;
361 foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents) 363// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
362 { 364// {
363 _httpd.RemoveAgentHandler(h.Key, h.Value); 365// _httpd.RemoveAgentHandler(h.Key, h.Value);
364 } 366// }
365 _agents = null; 367 _agents = null;
366 } 368 }
367 369
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index b3a4d61..c275d87 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -200,11 +200,25 @@ namespace OpenSim.Capabilities.Handlers
200 int start, end; 200 int start, end;
201 if (TryParseRange(range, out start, out end)) 201 if (TryParseRange(range, out start, out end))
202 { 202 {
203
204 // Before clamping start make sure we can satisfy it in order to avoid 203 // Before clamping start make sure we can satisfy it in order to avoid
205 // sending back the last byte instead of an error status 204 // sending back the last byte instead of an error status
206 if (start >= texture.Data.Length) 205 if (start >= texture.Data.Length)
207 { 206 {
207// m_log.DebugFormat(
208// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
209// texture.ID, start, texture.Data.Length);
210
211 // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
212 // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
213 // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
214 // received a very small texture may attempt to fetch bytes from the server past the
215 // range of data that it received originally. Whether this happens appears to depend on whether
216 // the viewer's estimation of how large a request it needs to make for certain discard levels
217 // (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
218 // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
219 // here will cause the viewer to treat the texture as bad and never display the full resolution
220 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
221
208// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 222// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
209 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters 223 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
210 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; 224 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
@@ -215,7 +229,7 @@ namespace OpenSim.Capabilities.Handlers
215 start = Utils.Clamp(start, 0, end); 229 start = Utils.Clamp(start, 0, end);
216 int len = end - start + 1; 230 int len = end - start + 1;
217 231
218 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 232// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
219 233
220 response["content-type"] = texture.Metadata.ContentType; 234 response["content-type"] = texture.Metadata.ContentType;
221 235
diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs
index 546b5e8..70e1065 100644
--- a/OpenSim/Data/IRegionData.cs
+++ b/OpenSim/Data/IRegionData.cs
@@ -85,21 +85,6 @@ namespace OpenSim.Data
85 List<RegionData> GetHyperlinks(UUID scopeID); 85 List<RegionData> GetHyperlinks(UUID scopeID);
86 } 86 }
87 87
88 [Flags]
89 public enum RegionFlags : int
90 {
91 DefaultRegion = 1, // Used for new Rez. Random if multiple defined
92 FallbackRegion = 2, // Regions we redirect to when the destination is down
93 RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
94 NoDirectLogin = 8, // Region unavailable for direct logins (by name)
95 Persistent = 16, // Don't remove on unregister
96 LockedOut = 32, // Don't allow registration
97 NoMove = 64, // Don't allow moving this region
98 Reservation = 128, // This is an inactive reservation
99 Authenticate = 256, // Require authentication
100 Hyperlink = 512 // Record represents a HG link
101 }
102
103 public class RegionDataDistanceCompare : IComparer<RegionData> 88 public class RegionDataDistanceCompare : IComparer<RegionData>
104 { 89 {
105 private Vector2 m_origin; 90 private Vector2 m_origin;
diff --git a/OpenSim/Data/IXInventoryData.cs b/OpenSim/Data/IXInventoryData.cs
index 85a5c08..e64a828 100644
--- a/OpenSim/Data/IXInventoryData.cs
+++ b/OpenSim/Data/IXInventoryData.cs
@@ -40,6 +40,11 @@ namespace OpenSim.Data
40 public UUID folderID; 40 public UUID folderID;
41 public UUID agentID; 41 public UUID agentID;
42 public UUID parentFolderID; 42 public UUID parentFolderID;
43
44 public XInventoryFolder Clone()
45 {
46 return (XInventoryFolder)MemberwiseClone();
47 }
43 } 48 }
44 49
45 public class XInventoryItem 50 public class XInventoryItem
@@ -64,6 +69,11 @@ namespace OpenSim.Data
64 public UUID avatarID; 69 public UUID avatarID;
65 public UUID parentFolderID; 70 public UUID parentFolderID;
66 public int inventoryGroupPermissions; 71 public int inventoryGroupPermissions;
72
73 public XInventoryItem Clone()
74 {
75 return (XInventoryItem)MemberwiseClone();
76 }
67 } 77 }
68 78
69 public interface IXInventoryData 79 public interface IXInventoryData
diff --git a/OpenSim/Data/MSSQL/MSSQLRegionData.cs b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
index 3ae87c3..0d89706 100644
--- a/OpenSim/Data/MSSQL/MSSQLRegionData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
@@ -37,6 +37,7 @@ using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using RegionFlags = OpenSim.Framework.RegionFlags;
40 41
41namespace OpenSim.Data.MSSQL 42namespace OpenSim.Data.MSSQL
42{ 43{
diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs
index 0614879..a2d4ae4 100644
--- a/OpenSim/Data/MySQL/MySQLRegionData.cs
+++ b/OpenSim/Data/MySQL/MySQLRegionData.cs
@@ -30,11 +30,11 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Data; 31using System.Data;
32using System.Reflection; 32using System.Reflection;
33 33using MySql.Data.MySqlClient;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Data; 36using OpenSim.Data;
37using MySql.Data.MySqlClient; 37using RegionFlags = OpenSim.Framework.RegionFlags;
38 38
39namespace OpenSim.Data.MySQL 39namespace OpenSim.Data.MySQL
40{ 40{
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 4d7c0c9..12c979a 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -747,95 +747,99 @@ namespace OpenSim.Data.MySQL
747 RegionLightShareData nWP = new RegionLightShareData(); 747 RegionLightShareData nWP = new RegionLightShareData();
748 nWP.OnSave += StoreRegionWindlightSettings; 748 nWP.OnSave += StoreRegionWindlightSettings;
749 749
750 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 750 lock (m_dbLock)
751 { 751 {
752 dbcon.Open(); 752 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
753
754 string command = "select * from `regionwindlight` where region_id = ?regionID";
755
756 using (MySqlCommand cmd = new MySqlCommand(command))
757 { 753 {
758 cmd.Connection = dbcon; 754 dbcon.Open();
759 755
760 cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString()); 756 string command = "select * from `regionwindlight` where region_id = ?regionID";
761 757
762 IDataReader result = ExecuteReader(cmd); 758 using (MySqlCommand cmd = new MySqlCommand(command))
763 if (!result.Read())
764 {
765 //No result, so store our default windlight profile and return it
766 nWP.regionID = regionUUID;
767 // StoreRegionWindlightSettings(nWP);
768 return nWP;
769 }
770 else
771 { 759 {
772 nWP.regionID = DBGuid.FromDB(result["region_id"]); 760 cmd.Connection = dbcon;
773 nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]); 761
774 nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]); 762 cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString());
775 nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]); 763
776 nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]); 764 IDataReader result = ExecuteReader(cmd);
777 nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]); 765 if (!result.Read())
778 nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]); 766 {
779 nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]); 767 //No result, so store our default windlight profile and return it
780 nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]); 768 nWP.regionID = regionUUID;
781 nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]); 769// StoreRegionWindlightSettings(nWP);
782 nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]); 770 return nWP;
783 nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]); 771 }
784 nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]); 772 else
785 nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]); 773 {
786 nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]); 774 nWP.regionID = DBGuid.FromDB(result["region_id"]);
787 nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]); 775 nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]);
788 nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]); 776 nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]);
789 nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]); 777 nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]);
790 UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture); 778 nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]);
791 nWP.horizon.X = Convert.ToSingle(result["horizon_r"]); 779 nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]);
792 nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]); 780 nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]);
793 nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]); 781 nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]);
794 nWP.horizon.W = Convert.ToSingle(result["horizon_i"]); 782 nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]);
795 nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]); 783 nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]);
796 nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]); 784 nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]);
797 nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]); 785 nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]);
798 nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]); 786 nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]);
799 nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]); 787 nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]);
800 nWP.hazeDensity = Convert.ToSingle(result["haze_density"]); 788 nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]);
801 nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]); 789 nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]);
802 nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]); 790 nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]);
803 nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]); 791 nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]);
804 nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]); 792 UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture);
805 nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]); 793 nWP.horizon.X = Convert.ToSingle(result["horizon_r"]);
806 nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]); 794 nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]);
807 nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]); 795 nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]);
808 nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]); 796 nWP.horizon.W = Convert.ToSingle(result["horizon_i"]);
809 nWP.ambient.X = Convert.ToSingle(result["ambient_r"]); 797 nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]);
810 nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]); 798 nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]);
811 nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]); 799 nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]);
812 nWP.ambient.W = Convert.ToSingle(result["ambient_i"]); 800 nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]);
813 nWP.eastAngle = Convert.ToSingle(result["east_angle"]); 801 nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]);
814 nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]); 802 nWP.hazeDensity = Convert.ToSingle(result["haze_density"]);
815 nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]); 803 nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]);
816 nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]); 804 nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]);
817 nWP.starBrightness = Convert.ToSingle(result["star_brightness"]); 805 nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]);
818 nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]); 806 nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]);
819 nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]); 807 nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]);
820 nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]); 808 nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]);
821 nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]); 809 nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]);
822 nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]); 810 nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]);
823 nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]); 811 nWP.ambient.X = Convert.ToSingle(result["ambient_r"]);
824 nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]); 812 nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]);
825 nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]); 813 nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]);
826 nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]); 814 nWP.ambient.W = Convert.ToSingle(result["ambient_i"]);
827 nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]); 815 nWP.eastAngle = Convert.ToSingle(result["east_angle"]);
828 nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]); 816 nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]);
829 nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]); 817 nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]);
830 nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]); 818 nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]);
831 nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]); 819 nWP.starBrightness = Convert.ToSingle(result["star_brightness"]);
832 nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]); 820 nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]);
833 nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]); 821 nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]);
834 nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]); 822 nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]);
835 nWP.valid = true; 823 nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]);
824 nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]);
825 nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]);
826 nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]);
827 nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]);
828 nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]);
829 nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]);
830 nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]);
831 nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]);
832 nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]);
833 nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]);
834 nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]);
835 nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]);
836 nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]);
837 nWP.valid = true;
838 }
836 } 839 }
837 } 840 }
838 } 841 }
842
839 return nWP; 843 return nWP;
840 } 844 }
841 845
@@ -881,118 +885,124 @@ namespace OpenSim.Data.MySQL
881 885
882 public virtual void StoreRegionWindlightSettings(RegionLightShareData wl) 886 public virtual void StoreRegionWindlightSettings(RegionLightShareData wl)
883 { 887 {
884 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 888 lock (m_dbLock)
885 { 889 {
886 dbcon.Open(); 890 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
887
888 using (MySqlCommand cmd = dbcon.CreateCommand())
889 { 891 {
890 cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, "; 892 dbcon.Open();
891 cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, "; 893
892 cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, "; 894 using (MySqlCommand cmd = dbcon.CreateCommand())
893 cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, "; 895 {
894 cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, "; 896 cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, ";
895 cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, "; 897 cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, ";
896 cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, "; 898 cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, ";
897 cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, "; 899 cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, ";
898 cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, "; 900 cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, ";
899 cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, "; 901 cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, ";
900 cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, "; 902 cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, ";
901 cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, "; 903 cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, ";
902 cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, "; 904 cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, ";
903 cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, "; 905 cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, ";
904 cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, "; 906 cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, ";
905 cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, "; 907 cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, ";
906 cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, "; 908 cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, ";
907 cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, "; 909 cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, ";
908 cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, "; 910 cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, ";
909 cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, "; 911 cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, ";
910 cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, "; 912 cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, ";
911 cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, "; 913 cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, ";
912 cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, "; 914 cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, ";
913 cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, "; 915 cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, ";
914 cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)"; 916 cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, ";
915 917 cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, ";
916 cmd.Parameters.AddWithValue("region_id", wl.regionID); 918 cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, ";
917 cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X); 919 cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, ";
918 cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y); 920 cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)";
919 cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z); 921
920 cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent); 922 cmd.Parameters.AddWithValue("region_id", wl.regionID);
921 cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier); 923 cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X);
922 cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X); 924 cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y);
923 cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y); 925 cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z);
924 cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z); 926 cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent);
925 cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale); 927 cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier);
926 cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset); 928 cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X);
927 cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove); 929 cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y);
928 cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow); 930 cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z);
929 cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier); 931 cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale);
930 cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X); 932 cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset);
931 cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y); 933 cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove);
932 cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X); 934 cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow);
933 cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y); 935 cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier);
934 cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture); 936 cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X);
935 cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X); 937 cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y);
936 cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y); 938 cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X);
937 cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z); 939 cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y);
938 cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W); 940 cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture);
939 cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon); 941 cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X);
940 cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X); 942 cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y);
941 cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y); 943 cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z);
942 cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z); 944 cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W);
943 cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W); 945 cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon);
944 cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity); 946 cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X);
945 cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier); 947 cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y);
946 cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier); 948 cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z);
947 cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude); 949 cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W);
948 cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X); 950 cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity);
949 cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y); 951 cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier);
950 cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z); 952 cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier);
951 cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W); 953 cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude);
952 cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition); 954 cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X);
953 cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X); 955 cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y);
954 cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y); 956 cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z);
955 cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z); 957 cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W);
956 cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W); 958 cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition);
957 cmd.Parameters.AddWithValue("east_angle", wl.eastAngle); 959 cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X);
958 cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus); 960 cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y);
959 cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize); 961 cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z);
960 cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma); 962 cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W);
961 cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness); 963 cmd.Parameters.AddWithValue("east_angle", wl.eastAngle);
962 cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X); 964 cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus);
963 cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y); 965 cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize);
964 cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z); 966 cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma);
965 cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W); 967 cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness);
966 cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X); 968 cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X);
967 cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y); 969 cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y);
968 cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z); 970 cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z);
969 cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage); 971 cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W);
970 cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale); 972 cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X);
971 cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X); 973 cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y);
972 cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y); 974 cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z);
973 cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z); 975 cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage);
974 cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX); 976 cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale);
975 cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock); 977 cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X);
976 cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); 978 cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y);
977 cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); 979 cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z);
978 cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); 980 cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX);
979 981 cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock);
980 ExecuteNonQuery(cmd); 982 cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY);
983 cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock);
984 cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds);
985
986 ExecuteNonQuery(cmd);
987 }
981 } 988 }
982 } 989 }
983 } 990 }
984 991
985 public virtual void RemoveRegionWindlightSettings(UUID regionID) 992 public virtual void RemoveRegionWindlightSettings(UUID regionID)
986 { 993 {
987 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 994 lock (m_dbLock)
988 { 995 {
989 dbcon.Open(); 996 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
990
991 using (MySqlCommand cmd = dbcon.CreateCommand())
992 { 997 {
993 cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID"; 998 dbcon.Open();
994 cmd.Parameters.AddWithValue("?regionID", regionID.ToString()); 999
995 ExecuteNonQuery(cmd); 1000 using (MySqlCommand cmd = dbcon.CreateCommand())
1001 {
1002 cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID";
1003 cmd.Parameters.AddWithValue("?regionID", regionID.ToString());
1004 ExecuteNonQuery(cmd);
1005 }
996 } 1006 }
997 } 1007 }
998 } 1008 }
@@ -1000,26 +1010,29 @@ namespace OpenSim.Data.MySQL
1000 #region RegionEnvironmentSettings 1010 #region RegionEnvironmentSettings
1001 public string LoadRegionEnvironmentSettings(UUID regionUUID) 1011 public string LoadRegionEnvironmentSettings(UUID regionUUID)
1002 { 1012 {
1003 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 1013 lock (m_dbLock)
1004 { 1014 {
1005 dbcon.Open(); 1015 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
1006
1007 string command = "select * from `regionenvironment` where region_id = ?region_id";
1008
1009 using (MySqlCommand cmd = new MySqlCommand(command))
1010 { 1016 {
1011 cmd.Connection = dbcon; 1017 dbcon.Open();
1012 1018
1013 cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); 1019 string command = "select * from `regionenvironment` where region_id = ?region_id";
1014 1020
1015 IDataReader result = ExecuteReader(cmd); 1021 using (MySqlCommand cmd = new MySqlCommand(command))
1016 if (!result.Read())
1017 {
1018 return String.Empty;
1019 }
1020 else
1021 { 1022 {
1022 return Convert.ToString(result["llsd_settings"]); 1023 cmd.Connection = dbcon;
1024
1025 cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
1026
1027 IDataReader result = ExecuteReader(cmd);
1028 if (!result.Read())
1029 {
1030 return String.Empty;
1031 }
1032 else
1033 {
1034 return Convert.ToString(result["llsd_settings"]);
1035 }
1023 } 1036 }
1024 } 1037 }
1025 } 1038 }
@@ -1027,33 +1040,39 @@ namespace OpenSim.Data.MySQL
1027 1040
1028 public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) 1041 public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings)
1029 { 1042 {
1030 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 1043 lock (m_dbLock)
1031 { 1044 {
1032 dbcon.Open(); 1045 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
1033
1034 using (MySqlCommand cmd = dbcon.CreateCommand())
1035 { 1046 {
1036 cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)"; 1047 dbcon.Open();
1037 1048
1038 cmd.Parameters.AddWithValue("region_id", regionUUID); 1049 using (MySqlCommand cmd = dbcon.CreateCommand())
1039 cmd.Parameters.AddWithValue("llsd_settings", settings); 1050 {
1040 1051 cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)";
1041 ExecuteNonQuery(cmd); 1052
1053 cmd.Parameters.AddWithValue("region_id", regionUUID);
1054 cmd.Parameters.AddWithValue("llsd_settings", settings);
1055
1056 ExecuteNonQuery(cmd);
1057 }
1042 } 1058 }
1043 } 1059 }
1044 } 1060 }
1045 1061
1046 public void RemoveRegionEnvironmentSettings(UUID regionUUID) 1062 public void RemoveRegionEnvironmentSettings(UUID regionUUID)
1047 { 1063 {
1048 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 1064 lock (m_dbLock)
1049 { 1065 {
1050 dbcon.Open(); 1066 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
1051
1052 using (MySqlCommand cmd = dbcon.CreateCommand())
1053 { 1067 {
1054 cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id"; 1068 dbcon.Open();
1055 cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); 1069
1056 ExecuteNonQuery(cmd); 1070 using (MySqlCommand cmd = dbcon.CreateCommand())
1071 {
1072 cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id";
1073 cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString());
1074 ExecuteNonQuery(cmd);
1075 }
1057 } 1076 }
1058 } 1077 }
1059 } 1078 }
diff --git a/OpenSim/Data/MySQL/Resources/GridUserStore.migrations b/OpenSim/Data/MySQL/Resources/GridUserStore.migrations
index 32b85ee..d08e096 100644
--- a/OpenSim/Data/MySQL/Resources/GridUserStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/GridUserStore.migrations
@@ -17,3 +17,8 @@ CREATE TABLE `GridUser` (
17) ENGINE=InnoDB; 17) ENGINE=InnoDB;
18 18
19COMMIT; 19COMMIT;
20
21:VERSION 2 # --------------------------
22BEGIN;
23
24COMMIT;
diff --git a/OpenSim/Data/Null/NullRegionData.cs b/OpenSim/Data/Null/NullRegionData.cs
index deb50cb..b4d701a 100644
--- a/OpenSim/Data/Null/NullRegionData.cs
+++ b/OpenSim/Data/Null/NullRegionData.cs
@@ -33,6 +33,7 @@ using OpenSim.Framework;
33using OpenSim.Data; 33using OpenSim.Data;
34using System.Reflection; 34using System.Reflection;
35using log4net; 35using log4net;
36using RegionFlags = OpenSim.Framework.RegionFlags;
36 37
37namespace OpenSim.Data.Null 38namespace OpenSim.Data.Null
38{ 39{
diff --git a/OpenSim/Framework/AssetPermissions.cs b/OpenSim/Framework/AssetPermissions.cs
new file mode 100644
index 0000000..4a905c2
--- /dev/null
+++ b/OpenSim/Framework/AssetPermissions.cs
@@ -0,0 +1,84 @@
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4
5using Nini.Config;
6using log4net;
7
8using OpenMetaverse;
9
10namespace OpenSim.Framework
11{
12 public class AssetPermissions
13 {
14 private static readonly ILog m_log =
15 LogManager.GetLogger(
16 MethodBase.GetCurrentMethod().DeclaringType);
17
18 private bool[] m_DisallowExport, m_DisallowImport;
19 private string[] m_AssetTypeNames;
20
21 public AssetPermissions(IConfig config)
22 {
23 Type enumType = typeof(AssetType);
24 m_AssetTypeNames = Enum.GetNames(enumType);
25 for (int i = 0; i < m_AssetTypeNames.Length; i++)
26 m_AssetTypeNames[i] = m_AssetTypeNames[i].ToLower();
27 int n = Enum.GetValues(enumType).Length;
28 m_DisallowExport = new bool[n];
29 m_DisallowImport = new bool[n];
30
31 LoadPermsFromConfig(config, "DisallowExport", m_DisallowExport);
32 LoadPermsFromConfig(config, "DisallowImport", m_DisallowImport);
33
34 }
35
36 private void LoadPermsFromConfig(IConfig assetConfig, string variable, bool[] bitArray)
37 {
38 if (assetConfig == null)
39 return;
40
41 string perms = assetConfig.GetString(variable, String.Empty);
42 string[] parts = perms.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
43 foreach (string s in parts)
44 {
45 int index = Array.IndexOf(m_AssetTypeNames, s.Trim().ToLower());
46 if (index >= 0)
47 bitArray[index] = true;
48 else
49 m_log.WarnFormat("[Asset Permissions]: Invalid AssetType {0}", s);
50 }
51
52 }
53
54 public bool AllowedExport(sbyte type)
55 {
56 string assetTypeName = ((AssetType)type).ToString();
57
58 int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
59 if (index >= 0 && m_DisallowExport[index])
60 {
61 m_log.DebugFormat("[Asset Permissions]: Export denied: configuration does not allow export of AssetType {0}", assetTypeName);
62 return false;
63 }
64
65 return true;
66 }
67
68 public bool AllowedImport(sbyte type)
69 {
70 string assetTypeName = ((AssetType)type).ToString();
71
72 int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
73 if (index >= 0 && m_DisallowImport[index])
74 {
75 m_log.DebugFormat("[Asset Permissions]: Import denied: configuration does not allow import of AssetType {0}", assetTypeName);
76 return false;
77 }
78
79 return true;
80 }
81
82
83 }
84}
diff --git a/OpenSim/Framework/Cache.cs b/OpenSim/Framework/Cache.cs
index 79e20fc..31cab4a 100644
--- a/OpenSim/Framework/Cache.cs
+++ b/OpenSim/Framework/Cache.cs
@@ -199,7 +199,14 @@ namespace OpenSim.Framework
199 // 199 //
200 public class Cache 200 public class Cache
201 { 201 {
202 /// <summary>
203 /// Must only be accessed under lock.
204 /// </summary>
202 private List<CacheItemBase> m_Index = new List<CacheItemBase>(); 205 private List<CacheItemBase> m_Index = new List<CacheItemBase>();
206
207 /// <summary>
208 /// Must only be accessed under m_Index lock.
209 /// </summary>
203 private Dictionary<string, CacheItemBase> m_Lookup = 210 private Dictionary<string, CacheItemBase> m_Lookup =
204 new Dictionary<string, CacheItemBase>(); 211 new Dictionary<string, CacheItemBase>();
205 212
@@ -320,19 +327,19 @@ namespace OpenSim.Framework
320 { 327 {
321 if (m_Lookup.ContainsKey(index)) 328 if (m_Lookup.ContainsKey(index))
322 item = m_Lookup[index]; 329 item = m_Lookup[index];
323 }
324 330
325 if (item == null) 331 if (item == null)
326 { 332 {
333 Expire(true);
334 return null;
335 }
336
337 item.hits++;
338 item.lastUsed = DateTime.Now;
339
327 Expire(true); 340 Expire(true);
328 return null;
329 } 341 }
330 342
331 item.hits++;
332 item.lastUsed = DateTime.Now;
333
334 Expire(true);
335
336 return item; 343 return item;
337 } 344 }
338 345
@@ -385,7 +392,10 @@ namespace OpenSim.Framework
385 // 392 //
386 public Object Find(Predicate<CacheItemBase> d) 393 public Object Find(Predicate<CacheItemBase> d)
387 { 394 {
388 CacheItemBase item = m_Index.Find(d); 395 CacheItemBase item;
396
397 lock (m_Index)
398 item = m_Index.Find(d);
389 399
390 if (item == null) 400 if (item == null)
391 return null; 401 return null;
@@ -419,12 +429,12 @@ namespace OpenSim.Framework
419 public virtual void Store(string index, Object data, Type container, 429 public virtual void Store(string index, Object data, Type container,
420 Object[] parameters) 430 Object[] parameters)
421 { 431 {
422 Expire(false);
423
424 CacheItemBase item; 432 CacheItemBase item;
425 433
426 lock (m_Index) 434 lock (m_Index)
427 { 435 {
436 Expire(false);
437
428 if (m_Index.Contains(new CacheItemBase(index))) 438 if (m_Index.Contains(new CacheItemBase(index)))
429 { 439 {
430 if ((m_Flags & CacheFlags.AllowUpdate) != 0) 440 if ((m_Flags & CacheFlags.AllowUpdate) != 0)
@@ -450,9 +460,17 @@ namespace OpenSim.Framework
450 m_Index.Add(item); 460 m_Index.Add(item);
451 m_Lookup[index] = item; 461 m_Lookup[index] = item;
452 } 462 }
463
453 item.Store(data); 464 item.Store(data);
454 } 465 }
455 466
467 /// <summary>
468 /// Expire items as appropriate.
469 /// </summary>
470 /// <remarks>
471 /// Callers must lock m_Index.
472 /// </remarks>
473 /// <param name='getting'></param>
456 protected virtual void Expire(bool getting) 474 protected virtual void Expire(bool getting)
457 { 475 {
458 if (getting && (m_Strategy == CacheStrategy.Aggressive)) 476 if (getting && (m_Strategy == CacheStrategy.Aggressive))
@@ -475,12 +493,10 @@ namespace OpenSim.Framework
475 493
476 switch (m_Strategy) 494 switch (m_Strategy)
477 { 495 {
478 case CacheStrategy.Aggressive: 496 case CacheStrategy.Aggressive:
479 if (Count < Size) 497 if (Count < Size)
480 return; 498 return;
481 499
482 lock (m_Index)
483 {
484 m_Index.Sort(new SortLRU()); 500 m_Index.Sort(new SortLRU());
485 m_Index.Reverse(); 501 m_Index.Reverse();
486 502
@@ -490,7 +506,7 @@ namespace OpenSim.Framework
490 506
491 ExpireDelegate doExpire = OnExpire; 507 ExpireDelegate doExpire = OnExpire;
492 508
493 if (doExpire != null) 509 if (doExpire != null)
494 { 510 {
495 List<CacheItemBase> candidates = 511 List<CacheItemBase> candidates =
496 m_Index.GetRange(target, Count - target); 512 m_Index.GetRange(target, Count - target);
@@ -513,27 +529,34 @@ namespace OpenSim.Framework
513 foreach (CacheItemBase item in m_Index) 529 foreach (CacheItemBase item in m_Index)
514 m_Lookup[item.uuid] = item; 530 m_Lookup[item.uuid] = item;
515 } 531 }
516 } 532
517 break; 533 break;
518 default: 534
519 break; 535 default:
536 break;
520 } 537 }
521 } 538 }
522 539
523 public void Invalidate(string uuid) 540 public void Invalidate(string uuid)
524 { 541 {
525 if (!m_Lookup.ContainsKey(uuid)) 542 lock (m_Index)
526 return; 543 {
544 if (!m_Lookup.ContainsKey(uuid))
545 return;
527 546
528 CacheItemBase item = m_Lookup[uuid]; 547 CacheItemBase item = m_Lookup[uuid];
529 m_Lookup.Remove(uuid); 548 m_Lookup.Remove(uuid);
530 m_Index.Remove(item); 549 m_Index.Remove(item);
550 }
531 } 551 }
532 552
533 public void Clear() 553 public void Clear()
534 { 554 {
535 m_Index.Clear(); 555 lock (m_Index)
536 m_Lookup.Clear(); 556 {
557 m_Index.Clear();
558 m_Lookup.Clear();
559 }
537 } 560 }
538 } 561 }
539} 562} \ No newline at end of file
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
new file mode 100644
index 0000000..a7cf0c0
--- /dev/null
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -0,0 +1,114 @@
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.Linq;
31using System.Reflection;
32using log4net;
33using OpenMetaverse;
34
35public class ConsoleUtil
36{
37// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
38
39 public const string MinRawConsoleVectorValue = "-~";
40 public const string MaxRawConsoleVectorValue = "~";
41
42 public const string VectorSeparator = ",";
43 public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
44
45 /// <summary>
46 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
47 /// </summary>
48 /// <param name='rawConsoleVector'>/param>
49 /// <param name='vector'></param>
50 /// <returns></returns>
51 public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
52 {
53 return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
54 }
55
56 /// <summary>
57 /// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
58 /// </summary>
59 /// <param name='rawConsoleVector'>/param>
60 /// <param name='vector'></param>
61 /// <returns></returns>
62 public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
63 {
64 return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
65 }
66
67 /// <summary>
68 /// Convert a vector input from the console to an OpenMetaverse.Vector3
69 /// </summary>
70 /// <param name='rawConsoleVector'>
71 /// A string in the form <x>,<y>,<z> where there is no space between values.
72 /// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
73 /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
74 /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
75 /// Other than that, component values must be numeric.
76 /// </param>
77 /// <param name='blankComponentFunc'></param>
78 /// <param name='vector'></param>
79 /// <returns></returns>
80 public static bool TryParseConsoleVector(
81 string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
82 {
83 List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
84
85 if (components.Count < 1 || components.Count > 3)
86 {
87 vector = Vector3.Zero;
88 return false;
89 }
90
91 for (int i = components.Count; i < 3; i++)
92 components.Add("");
93
94 List<string> semiDigestedComponents
95 = components.ConvertAll<string>(
96 c =>
97 {
98 if (c == "")
99 return blankComponentFunc.Invoke(c);
100 else if (c == MaxRawConsoleVectorValue)
101 return float.MaxValue.ToString();
102 else if (c == MinRawConsoleVectorValue)
103 return float.MinValue.ToString();
104 else
105 return c;
106 });
107
108 string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
109
110// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
111
112 return Vector3.TryParse(semiDigestedConsoleVector, out vector);
113 }
114} \ No newline at end of file
diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs
index 1b1aaf2..a2eb5ee 100644
--- a/OpenSim/Framework/Constants.cs
+++ b/OpenSim/Framework/Constants.cs
@@ -31,6 +31,7 @@ namespace OpenSim.Framework
31 public class Constants 31 public class Constants
32 { 32 {
33 public const uint RegionSize = 256; 33 public const uint RegionSize = 256;
34 public const uint RegionHeight = 4096;
34 public const byte TerrainPatchSize = 16; 35 public const byte TerrainPatchSize = 16;
35 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; 36 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
36 37
diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs
index 9020761..e03750b 100644
--- a/OpenSim/Framework/EstateSettings.cs
+++ b/OpenSim/Framework/EstateSettings.cs
@@ -419,11 +419,11 @@ namespace OpenSim.Framework
419 419
420 public void SetFromFlags(ulong regionFlags) 420 public void SetFromFlags(ulong regionFlags)
421 { 421 {
422 ResetHomeOnTeleport = ((regionFlags & (ulong)RegionFlags.ResetHomeOnTeleport) == (ulong)RegionFlags.ResetHomeOnTeleport); 422 ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport);
423 BlockDwell = ((regionFlags & (ulong)RegionFlags.BlockDwell) == (ulong)RegionFlags.BlockDwell); 423 BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell);
424 AllowLandmark = ((regionFlags & (ulong)RegionFlags.AllowLandmark) == (ulong)RegionFlags.AllowLandmark); 424 AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark);
425 AllowParcelChanges = ((regionFlags & (ulong)RegionFlags.AllowParcelChanges) == (ulong)RegionFlags.AllowParcelChanges); 425 AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges);
426 AllowSetHome = ((regionFlags & (ulong)RegionFlags.AllowSetHome) == (ulong)RegionFlags.AllowSetHome); 426 AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome);
427 } 427 }
428 428
429 public bool GroupAccess(UUID groupID) 429 public bool GroupAccess(UUID groupID)
diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs
index a6bf6e3..6ae0488 100644
--- a/OpenSim/Framework/GridInstantMessage.cs
+++ b/OpenSim/Framework/GridInstantMessage.cs
@@ -44,7 +44,6 @@ namespace OpenSim.Framework
44 public Vector3 Position; 44 public Vector3 Position;
45 public byte[] binaryBucket; 45 public byte[] binaryBucket;
46 46
47
48 public uint ParentEstateID; 47 public uint ParentEstateID;
49 public Guid RegionID; 48 public Guid RegionID;
50 public uint timestamp; 49 public uint timestamp;
@@ -58,7 +57,7 @@ namespace OpenSim.Framework
58 string _fromAgentName, UUID _toAgentID, 57 string _fromAgentName, UUID _toAgentID,
59 byte _dialog, bool _fromGroup, string _message, 58 byte _dialog, bool _fromGroup, string _message,
60 UUID _imSessionID, bool _offline, Vector3 _position, 59 UUID _imSessionID, bool _offline, Vector3 _position,
61 byte[] _binaryBucket) 60 byte[] _binaryBucket, bool addTimestamp)
62 { 61 {
63 fromAgentID = _fromAgentID.Guid; 62 fromAgentID = _fromAgentID.Guid;
64 fromAgentName = _fromAgentName; 63 fromAgentName = _fromAgentName;
@@ -79,7 +78,9 @@ namespace OpenSim.Framework
79 ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID; 78 ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID;
80 RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid; 79 RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid;
81 } 80 }
82 timestamp = (uint)Util.UnixTimeSinceEpoch(); 81
82 if (addTimestamp)
83 timestamp = (uint)Util.UnixTimeSinceEpoch();
83 } 84 }
84 85
85 public GridInstantMessage(IScene scene, UUID _fromAgentID, 86 public GridInstantMessage(IScene scene, UUID _fromAgentID,
@@ -87,7 +88,7 @@ namespace OpenSim.Framework
87 string _message, bool _offline, 88 string _message, bool _offline,
88 Vector3 _position) : this(scene, _fromAgentID, _fromAgentName, 89 Vector3 _position) : this(scene, _fromAgentID, _fromAgentName,
89 _toAgentID, _dialog, false, _message, 90 _toAgentID, _dialog, false, _message,
90 _fromAgentID ^ _toAgentID, _offline, _position, new byte[0]) 91 _fromAgentID ^ _toAgentID, _offline, _position, new byte[0], true)
91 { 92 {
92 } 93 }
93 } 94 }
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 5909ce1..4ae533e 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -1046,8 +1046,21 @@ namespace OpenSim.Framework
1046 1046
1047 void InPacket(object NewPack); 1047 void InPacket(object NewPack);
1048 void ProcessInPacket(Packet NewPack); 1048 void ProcessInPacket(Packet NewPack);
1049
1050 /// <summary>
1051 /// Close this client
1052 /// </summary>
1049 void Close(); 1053 void Close();
1050 void Close(bool sendStop); 1054
1055 /// <summary>
1056 /// Close this client
1057 /// </summary>
1058 /// <param name='force'>
1059 /// If true, attempts the close without checking active status. You do not want to try this except as a last
1060 /// ditch attempt where Active == false but the ScenePresence still exists.
1061 /// </param>
1062 void Close(bool sendStop, bool force);
1063
1051 void Kick(string message); 1064 void Kick(string message);
1052 1065
1053 /// <summary> 1066 /// <summary>
diff --git a/OpenSim/Framework/InventoryFolderBase.cs b/OpenSim/Framework/InventoryFolderBase.cs
index a12183c..b3457a6 100644
--- a/OpenSim/Framework/InventoryFolderBase.cs
+++ b/OpenSim/Framework/InventoryFolderBase.cs
@@ -73,33 +73,27 @@ namespace OpenSim.Framework
73 { 73 {
74 } 74 }
75 75
76 public InventoryFolderBase(UUID id) 76 public InventoryFolderBase(UUID id) : this()
77 { 77 {
78 ID = id; 78 ID = id;
79 } 79 }
80 80
81 public InventoryFolderBase(UUID id, UUID owner) 81 public InventoryFolderBase(UUID id, UUID owner) : this(id)
82 { 82 {
83 ID = id;
84 Owner = owner; 83 Owner = owner;
85 } 84 }
86 85
87 public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) 86 public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) : this(id, owner)
88 { 87 {
89 ID = id;
90 Name = name; 88 Name = name;
91 Owner = owner;
92 ParentID = parent; 89 ParentID = parent;
93 } 90 }
94 91
95 public InventoryFolderBase(UUID id, string name, UUID owner, short type, UUID parent, ushort version) 92 public InventoryFolderBase(
93 UUID id, string name, UUID owner, short type, UUID parent, ushort version) : this(id, name, owner, parent)
96 { 94 {
97 ID = id;
98 Name = name;
99 Owner = owner;
100 Type = type; 95 Type = type;
101 ParentID = parent;
102 Version = version; 96 Version = version;
103 } 97 }
104 } 98 }
105} 99} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
index 9ee0876..446e3c0 100644
--- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
@@ -43,27 +43,32 @@ namespace OpenSim.Framework.Monitoring
43 StringBuilder sb = new StringBuilder(Environment.NewLine); 43 StringBuilder sb = new StringBuilder(Environment.NewLine);
44 sb.Append("MEMORY STATISTICS"); 44 sb.Append("MEMORY STATISTICS");
45 sb.Append(Environment.NewLine); 45 sb.Append(Environment.NewLine);
46 sb.Append( 46 sb.AppendFormat(
47 string.Format(
48 "Allocated to OpenSim objects: {0} MB\n", 47 "Allocated to OpenSim objects: {0} MB\n",
49 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0))); 48 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
49
50 sb.AppendFormat(
51 "OpenSim last object memory churn : {0} MB/s\n",
52 Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
53
54 sb.AppendFormat(
55 "OpenSim average object memory churn : {0} MB/s\n",
56 Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
50 57
51 Process myprocess = Process.GetCurrentProcess(); 58 Process myprocess = Process.GetCurrentProcess();
52 if (!myprocess.HasExited) 59 if (!myprocess.HasExited)
53 { 60 {
54 myprocess.Refresh(); 61 myprocess.Refresh();
55 sb.Append( 62 sb.AppendFormat(
56 string.Format(
57 "Process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n", 63 "Process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n",
58 Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0), 64 Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0),
59 Math.Round(Process.GetCurrentProcess().PagedMemorySize64 / 1024.0 / 1024.0), 65 Math.Round(Process.GetCurrentProcess().PagedMemorySize64 / 1024.0 / 1024.0),
60 Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0))); 66 Math.Round(Process.GetCurrentProcess().VirtualMemorySize64 / 1024.0 / 1024.0));
61 sb.Append( 67 sb.AppendFormat(
62 string.Format(
63 "Peak process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n", 68 "Peak process memory: Physical {0} MB \t Paged {1} MB \t Virtual {2} MB\n",
64 Math.Round(Process.GetCurrentProcess().PeakWorkingSet64 / 1024.0 / 1024.0), 69 Math.Round(Process.GetCurrentProcess().PeakWorkingSet64 / 1024.0 / 1024.0),
65 Math.Round(Process.GetCurrentProcess().PeakPagedMemorySize64 / 1024.0 / 1024.0), 70 Math.Round(Process.GetCurrentProcess().PeakPagedMemorySize64 / 1024.0 / 1024.0),
66 Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0))); 71 Math.Round(Process.GetCurrentProcess().PeakVirtualMemorySize64 / 1024.0 / 1024.0));
67 } 72 }
68 else 73 else
69 sb.Append("Process reported as Exited \n"); 74 sb.Append("Process reported as Exited \n");
diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
index a23cf1f..c6010cd 100644
--- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
+++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
@@ -60,7 +60,7 @@ namespace OpenSim.Framework.Monitoring
60 private static bool m_enabled; 60 private static bool m_enabled;
61 61
62 /// <summary> 62 /// <summary>
63 /// Average memory churn in bytes per millisecond. 63 /// Last memory churn in bytes per millisecond.
64 /// </summary> 64 /// </summary>
65 public static double AverageMemoryChurn 65 public static double AverageMemoryChurn
66 { 66 {
@@ -68,6 +68,14 @@ namespace OpenSim.Framework.Monitoring
68 } 68 }
69 69
70 /// <summary> 70 /// <summary>
71 /// Average memory churn in bytes per millisecond.
72 /// </summary>
73 public static double LastMemoryChurn
74 {
75 get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
76 }
77
78 /// <summary>
71 /// Maximum number of statistical samples. 79 /// Maximum number of statistical samples.
72 /// </summary> 80 /// </summary>
73 /// <remarks> 81 /// <remarks>
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index cdd7cc7..aa86202 100644
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -355,10 +355,25 @@ Asset service request failures: {3}" + Environment.NewLine,
355 sb.Append(Environment.NewLine); 355 sb.Append(Environment.NewLine);
356 sb.Append( 356 sb.Append(
357 string.Format( 357 string.Format(
358 "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}", 358 "{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n",
359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, 359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); 360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361 sb.Append(Environment.NewLine); 361
362 Dictionary<string, Dictionary<string, Stat>> sceneStats;
363
364 if (StatsManager.TryGetStats("scene", out sceneStats))
365 {
366 foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
367 {
368 foreach (Stat stat in kvp.Value.Values)
369 {
370 if (stat.Verbosity == StatVerbosity.Info)
371 {
372 sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
373 }
374 }
375 }
376 }
362 377
363 /* 378 /*
364 sb.Append(Environment.NewLine); 379 sb.Append(Environment.NewLine);
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index d78fa6a..31989e5 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -25,6 +25,9 @@
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;
29using System.Collections.Generic;
30
28namespace OpenSim.Framework.Monitoring 31namespace OpenSim.Framework.Monitoring
29{ 32{
30 /// <summary> 33 /// <summary>
@@ -32,6 +35,24 @@ namespace OpenSim.Framework.Monitoring
32 /// </summary> 35 /// </summary>
33 public class StatsManager 36 public class StatsManager
34 { 37 {
38 // Subcommand used to list other stats.
39 public const string AllSubCommand = "all";
40
41 // Subcommand used to list other stats.
42 public const string ListSubCommand = "list";
43
44 // All subcommands
45 public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
46
47 /// <summary>
48 /// Registered stats categorized by category/container/shortname
49 /// </summary>
50 /// <remarks>
51 /// Do not add or remove directly from this dictionary.
52 /// </remarks>
53 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
54 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
55
35 private static AssetStatsCollector assetStats; 56 private static AssetStatsCollector assetStats;
36 private static UserStatsCollector userStats; 57 private static UserStatsCollector userStats;
37 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); 58 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@@ -40,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
40 public static UserStatsCollector UserStats { get { return userStats; } } 61 public static UserStatsCollector UserStats { get { return userStats; } }
41 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 62 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
42 63
64 public static void RegisterConsoleCommands(ICommandConsole console)
65 {
66 console.Commands.AddCommand(
67 "General",
68 false,
69 "show stats",
70 "show stats [list|all|<category>]",
71 "Show statistical information for this server",
72 "If no final argument is specified then legacy statistics information is currently shown.\n"
73 + "If list is specified then statistic categories are shown.\n"
74 + "If all is specified then all registered statistics are shown.\n"
75 + "If a category name is specified then only statistics from that category are shown.\n"
76 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
77 HandleShowStatsCommand);
78 }
79
80 public static void HandleShowStatsCommand(string module, string[] cmd)
81 {
82 ICommandConsole con = MainConsole.Instance;
83
84 if (cmd.Length > 2)
85 {
86 var categoryName = cmd[2];
87
88 if (categoryName == AllSubCommand)
89 {
90 foreach (var category in RegisteredStats.Values)
91 {
92 OutputCategoryStatsToConsole(con, category);
93 }
94 }
95 else if (categoryName == ListSubCommand)
96 {
97 con.Output("Statistic categories available are:");
98 foreach (string category in RegisteredStats.Keys)
99 con.OutputFormat(" {0}", category);
100 }
101 else
102 {
103 Dictionary<string, Dictionary<string, Stat>> category;
104 if (!RegisteredStats.TryGetValue(categoryName, out category))
105 {
106 con.OutputFormat("No such category as {0}", categoryName);
107 }
108 else
109 {
110 OutputCategoryStatsToConsole(con, category);
111 }
112 }
113 }
114 else
115 {
116 // Legacy
117 con.Output(SimExtraStats.Report());
118 }
119 }
120
121 private static void OutputCategoryStatsToConsole(
122 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
123 {
124 foreach (var container in category.Values)
125 {
126 foreach (Stat stat in container.Values)
127 {
128 con.Output(stat.ToConsoleString());
129 }
130 }
131 }
132
43 /// <summary> 133 /// <summary>
44 /// Start collecting statistics related to assets. 134 /// Start collecting statistics related to assets.
45 /// Should only be called once. 135 /// Should only be called once.
@@ -61,5 +151,224 @@ namespace OpenSim.Framework.Monitoring
61 151
62 return userStats; 152 return userStats;
63 } 153 }
154
155 /// <summary>
156 /// Registers a statistic.
157 /// </summary>
158 /// <param name='stat'></param>
159 /// <returns></returns>
160 public static bool RegisterStat(Stat stat)
161 {
162 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
163 Dictionary<string, Stat> container = null, newContainer;
164
165 lock (RegisteredStats)
166 {
167 // Stat name is not unique across category/container/shortname key.
168 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
169 // in a class are run in the same instance of the VM.
170 if (TryGetStat(stat, out category, out container))
171 return false;
172
173 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
174 // This means that we don't need to lock or copy them on iteration, which will be a much more
175 // common operation after startup.
176 if (container != null)
177 newContainer = new Dictionary<string, Stat>(container);
178 else
179 newContainer = new Dictionary<string, Stat>();
180
181 if (category != null)
182 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
183 else
184 newCategory = new Dictionary<string, Dictionary<string, Stat>>();
185
186 newContainer[stat.ShortName] = stat;
187 newCategory[stat.Container] = newContainer;
188 RegisteredStats[stat.Category] = newCategory;
189 }
190
191 return true;
192 }
193
194 /// <summary>
195 /// Deregister a statistic
196 /// </summary>>
197 /// <param name='stat'></param>
198 /// <returns></returns
199 public static bool DeregisterStat(Stat stat)
200 {
201 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
202 Dictionary<string, Stat> container = null, newContainer;
203
204 lock (RegisteredStats)
205 {
206 if (!TryGetStat(stat, out category, out container))
207 return false;
208
209 newContainer = new Dictionary<string, Stat>(container);
210 newContainer.Remove(stat.UniqueName);
211
212 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
213 newCategory.Remove(stat.Container);
214
215 newCategory[stat.Container] = newContainer;
216 RegisteredStats[stat.Category] = newCategory;
217
218 return true;
219 }
220 }
221
222 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
223 {
224 return RegisteredStats.TryGetValue(category, out stats);
225 }
226
227 public static bool TryGetStat(
228 Stat stat,
229 out Dictionary<string, Dictionary<string, Stat>> category,
230 out Dictionary<string, Stat> container)
231 {
232 category = null;
233 container = null;
234
235 lock (RegisteredStats)
236 {
237 if (RegisteredStats.TryGetValue(stat.Category, out category))
238 {
239 if (category.TryGetValue(stat.Container, out container))
240 {
241 if (container.ContainsKey(stat.ShortName))
242 return true;
243 }
244 }
245 }
246
247 return false;
248 }
249 }
250
251 /// <summary>
252 /// Verbosity of stat.
253 /// </summary>
254 /// <remarks>
255 /// Info will always be displayed.
256 /// </remarks>
257 public enum StatVerbosity
258 {
259 Debug,
260 Info
261 }
262
263 /// <summary>
264 /// Holds individual static details
265 /// </summary>
266 public class Stat
267 {
268 /// <summary>
269 /// Unique stat name used for indexing. Each ShortName in a Category must be unique.
270 /// </summary>
271 public string UniqueName { get; private set; }
272
273 /// <summary>
274 /// Category of this stat (e.g. cache, scene, etc).
275 /// </summary>
276 public string Category { get; private set; }
277
278 /// <summary>
279 /// Containing name for this stat.
280 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
281 /// us with a to-be-resolved problem of non-unique region names).
282 /// </summary>
283 /// <value>
284 /// The container.
285 /// </value>
286 public string Container { get; private set; }
287
288 public StatVerbosity Verbosity { get; private set; }
289 public string ShortName { get; private set; }
290 public string Name { get; private set; }
291 public string Description { get; private set; }
292 public virtual string UnitName { get; private set; }
293
294 public virtual double Value { get; set; }
295
296 /// <summary>
297 /// Constructor
298 /// </summary>
299 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
300 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
301 /// <param name='unitName'>
302 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
303 /// e.g. " frames"
304 /// </param>
305 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
306 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
307 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
308 /// <param name='description'>Description of stat</param>
309 public Stat(
310 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
311 {
312 if (StatsManager.SubCommands.Contains(category))
313 throw new Exception(
314 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
315
316 ShortName = shortName;
317 Name = name;
318 UnitName = unitName;
319 Category = category;
320 Container = container;
321 Verbosity = verbosity;
322 Description = description;
323
324 UniqueName = GenUniqueName(Container, Category, ShortName);
325 }
326
327 public static string GenUniqueName(string container, string category, string shortName)
328 {
329 return string.Format("{0}+{1}+{2}", container, category, shortName);
330 }
331
332 public virtual string ToConsoleString()
333 {
334 return string.Format(
335 "{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
336 }
337 }
338
339 public class PercentageStat : Stat
340 {
341 public int Antecedent { get; set; }
342 public int Consequent { get; set; }
343
344 public override double Value
345 {
346 get
347 {
348 int c = Consequent;
349
350 // Avoid any chance of a multi-threaded divide-by-zero
351 if (c == 0)
352 return 0;
353
354 return (double)Antecedent / c * 100;
355 }
356
357 set
358 {
359 throw new Exception("Cannot set value on a PercentageStat");
360 }
361 }
362
363 public PercentageStat(
364 string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
365 : base(shortName, name, "%", category, container, verbosity, description) {}
366
367 public override string ToConsoleString()
368 {
369 return string.Format(
370 "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
371 Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
372 }
64 } 373 }
65} \ No newline at end of file 374} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index b709baa..28d6d5c 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -89,6 +89,17 @@ namespace OpenSim.Framework.Monitoring
89 FirstTick = Environment.TickCount & Int32.MaxValue; 89 FirstTick = Environment.TickCount & Int32.MaxValue;
90 LastTick = FirstTick; 90 LastTick = FirstTick;
91 } 91 }
92
93 public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
94 {
95 Thread = previousTwi.Thread;
96 FirstTick = previousTwi.FirstTick;
97 LastTick = previousTwi.LastTick;
98 Timeout = previousTwi.Timeout;
99 IsTimedOut = previousTwi.IsTimedOut;
100 AlarmIfTimeout = previousTwi.AlarmIfTimeout;
101 AlarmMethod = previousTwi.AlarmMethod;
102 }
92 } 103 }
93 104
94 /// <summary> 105 /// <summary>
@@ -220,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
220 private static bool RemoveThread(int threadID) 231 private static bool RemoveThread(int threadID)
221 { 232 {
222 lock (m_threads) 233 lock (m_threads)
223 return m_threads.Remove(threadID); 234 {
235 ThreadWatchdogInfo twi;
236 if (m_threads.TryGetValue(threadID, out twi))
237 {
238 m_log.DebugFormat(
239 "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
240
241 m_threads.Remove(threadID);
242
243 return true;
244 }
245 else
246 {
247 m_log.WarnFormat(
248 "[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
249
250 return false;
251 }
252 }
224 } 253 }
225 254
226 public static bool AbortThread(int threadID) 255 public static bool AbortThread(int threadID)
@@ -335,7 +364,9 @@ namespace OpenSim.Framework.Monitoring
335 if (callbackInfos == null) 364 if (callbackInfos == null)
336 callbackInfos = new List<ThreadWatchdogInfo>(); 365 callbackInfos = new List<ThreadWatchdogInfo>();
337 366
338 callbackInfos.Add(threadInfo); 367 // Send a copy of the watchdog info to prevent race conditions where the watchdog
368 // thread updates the monitoring info after an alarm has been sent out.
369 callbackInfos.Add(new ThreadWatchdogInfo(threadInfo));
339 } 370 }
340 } 371 }
341 } 372 }
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGUuidGatherer.cs b/OpenSim/Framework/Pool.cs
index fcb544f..1ca06c3 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGUuidGatherer.cs
+++ b/OpenSim/Framework/Pool.cs
@@ -28,30 +28,49 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30 30
31using OpenSim.Framework; 31namespace OpenSim.Framework
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Services.Interfaces;
34using OpenMetaverse;
35
36namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
37{ 32{
38 public class HGUuidGatherer : UuidGatherer 33 /// <summary>
34 /// Naive pool implementation.
35 /// </summary>
36 /// <remarks>
37 /// Currently assumes that objects are in a useable state when returned.
38 /// </remarks>
39 public class Pool<T>
39 { 40 {
40 protected string m_assetServerURL; 41 private Stack<T> m_pool;
41 protected HGAssetMapper m_assetMapper; 42
43 private int m_maxPoolSize;
44
45 private Func<T> m_createFunction;
46
47 public Pool(Func<T> createFunction, int maxSize)
48 {
49 m_maxPoolSize = maxSize;
50 m_createFunction = createFunction;
51 m_pool = new Stack<T>(m_maxPoolSize);
52 }
42 53
43 public HGUuidGatherer(HGAssetMapper assMap, IAssetService assetCache, string assetServerURL) : base(assetCache) 54 public T GetObject()
44 { 55 {
45 m_assetMapper = assMap; 56 lock (m_pool)
46 m_assetServerURL = assetServerURL; 57 {
58 if (m_pool.Count > 0)
59 return m_pool.Pop();
60 else
61 return m_createFunction();
62 }
47 } 63 }
48 64
49 protected override AssetBase GetAsset(UUID uuid) 65 public void ReturnObject(T obj)
50 { 66 {
51 if (string.Empty == m_assetServerURL) 67 lock (m_pool)
52 return m_assetCache.Get(uuid.ToString()); 68 {
53 else 69 if (m_pool.Count >= m_maxPoolSize)
54 return m_assetMapper.FetchAsset(m_assetServerURL, uuid); 70 return;
71 else
72 m_pool.Push(obj);
73 }
55 } 74 }
56 } 75 }
57} 76} \ No newline at end of file
diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs
new file mode 100644
index 0000000..a3089b0
--- /dev/null
+++ b/OpenSim/Framework/RegionFlags.cs
@@ -0,0 +1,53 @@
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;
29
30namespace OpenSim.Framework
31{
32 /// <summary>
33 /// Region flags used internally by OpenSimulator to store installation specific information about regions.
34 /// </summary>
35 /// <remarks>
36 /// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
37 /// Returned by IGridService.GetRegionFlags()
38 /// </remarks>
39 [Flags]
40 public enum RegionFlags : int
41 {
42 DefaultRegion = 1, // Used for new Rez. Random if multiple defined
43 FallbackRegion = 2, // Regions we redirect to when the destination is down
44 RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
45 NoDirectLogin = 8, // Region unavailable for direct logins (by name)
46 Persistent = 16, // Don't remove on unregister
47 LockedOut = 32, // Don't allow registration
48 NoMove = 64, // Don't allow moving this region
49 Reservation = 128, // This is an inactive reservation
50 Authenticate = 256, // Require authentication
51 Hyperlink = 512 // Record represents a HG link
52 }
53} \ No newline at end of file
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index 4bde7be..e7bed6a 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -122,10 +122,13 @@ namespace OpenSim.Framework
122 public UUID lastMapUUID = UUID.Zero; 122 public UUID lastMapUUID = UUID.Zero;
123 public string lastMapRefresh = "0"; 123 public string lastMapRefresh = "0";
124 124
125 private float m_nonphysPrimMin = 0;
125 private int m_nonphysPrimMax = 0; 126 private int m_nonphysPrimMax = 0;
127 private float m_physPrimMin = 0;
126 private int m_physPrimMax = 0; 128 private int m_physPrimMax = 0;
127 private bool m_clampPrimSize = false; 129 private bool m_clampPrimSize = false;
128 private int m_objectCapacity = 0; 130 private int m_objectCapacity = 0;
131 private int m_linksetCapacity = 0;
129 private int m_agentCapacity = 0; 132 private int m_agentCapacity = 0;
130 private string m_regionType = String.Empty; 133 private string m_regionType = String.Empty;
131 private RegionLightShareData m_windlight = new RegionLightShareData(); 134 private RegionLightShareData m_windlight = new RegionLightShareData();
@@ -287,11 +290,21 @@ namespace OpenSim.Framework
287 set { m_windlight = value; } 290 set { m_windlight = value; }
288 } 291 }
289 292
293 public float NonphysPrimMin
294 {
295 get { return m_nonphysPrimMin; }
296 }
297
290 public int NonphysPrimMax 298 public int NonphysPrimMax
291 { 299 {
292 get { return m_nonphysPrimMax; } 300 get { return m_nonphysPrimMax; }
293 } 301 }
294 302
303 public float PhysPrimMin
304 {
305 get { return m_physPrimMin; }
306 }
307
295 public int PhysPrimMax 308 public int PhysPrimMax
296 { 309 {
297 get { return m_physPrimMax; } 310 get { return m_physPrimMax; }
@@ -307,6 +320,11 @@ namespace OpenSim.Framework
307 get { return m_objectCapacity; } 320 get { return m_objectCapacity; }
308 } 321 }
309 322
323 public int LinksetCapacity
324 {
325 get { return m_linksetCapacity; }
326 }
327
310 public int AgentCapacity 328 public int AgentCapacity
311 { 329 {
312 get { return m_agentCapacity; } 330 get { return m_agentCapacity; }
@@ -625,16 +643,31 @@ namespace OpenSim.Framework
625 m_regionType = config.GetString("RegionType", String.Empty); 643 m_regionType = config.GetString("RegionType", String.Empty);
626 allKeys.Remove("RegionType"); 644 allKeys.Remove("RegionType");
627 645
628 // Prim stuff 646 #region Prim stuff
629 // 647
630 m_nonphysPrimMax = config.GetInt("NonphysicalPrimMax", 0); 648 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
631 allKeys.Remove("NonphysicalPrimMax"); 649 allKeys.Remove("NonPhysicalPrimMin");
650
651 m_nonphysPrimMax = config.GetInt("NonPhysicalPrimMax", 0);
652 allKeys.Remove("NonPhysicalPrimMax");
653
654 m_physPrimMin = config.GetFloat("PhysicalPrimMin", 0);
655 allKeys.Remove("PhysicalPrimMin");
656
632 m_physPrimMax = config.GetInt("PhysicalPrimMax", 0); 657 m_physPrimMax = config.GetInt("PhysicalPrimMax", 0);
633 allKeys.Remove("PhysicalPrimMax"); 658 allKeys.Remove("PhysicalPrimMax");
659
634 m_clampPrimSize = config.GetBoolean("ClampPrimSize", false); 660 m_clampPrimSize = config.GetBoolean("ClampPrimSize", false);
635 allKeys.Remove("ClampPrimSize"); 661 allKeys.Remove("ClampPrimSize");
662
636 m_objectCapacity = config.GetInt("MaxPrims", 15000); 663 m_objectCapacity = config.GetInt("MaxPrims", 15000);
637 allKeys.Remove("MaxPrims"); 664 allKeys.Remove("MaxPrims");
665
666 m_linksetCapacity = config.GetInt("LinksetPrims", 0);
667 allKeys.Remove("LinksetPrims");
668
669 #endregion
670
638 m_agentCapacity = config.GetInt("MaxAgents", 100); 671 m_agentCapacity = config.GetInt("MaxAgents", 100);
639 allKeys.Remove("MaxAgents"); 672 allKeys.Remove("MaxAgents");
640 673
@@ -673,16 +706,27 @@ namespace OpenSim.Framework
673 706
674 config.Set("ExternalHostName", m_externalHostName); 707 config.Set("ExternalHostName", m_externalHostName);
675 708
676 if (m_nonphysPrimMax != 0) 709 if (m_nonphysPrimMin > 0)
710 config.Set("NonphysicalPrimMax", m_nonphysPrimMin);
711
712 if (m_nonphysPrimMax > 0)
677 config.Set("NonphysicalPrimMax", m_nonphysPrimMax); 713 config.Set("NonphysicalPrimMax", m_nonphysPrimMax);
678 if (m_physPrimMax != 0) 714
715 if (m_physPrimMin > 0)
716 config.Set("PhysicalPrimMax", m_physPrimMin);
717
718 if (m_physPrimMax > 0)
679 config.Set("PhysicalPrimMax", m_physPrimMax); 719 config.Set("PhysicalPrimMax", m_physPrimMax);
720
680 config.Set("ClampPrimSize", m_clampPrimSize.ToString()); 721 config.Set("ClampPrimSize", m_clampPrimSize.ToString());
681 722
682 if (m_objectCapacity != 0) 723 if (m_objectCapacity > 0)
683 config.Set("MaxPrims", m_objectCapacity); 724 config.Set("MaxPrims", m_objectCapacity);
684 725
685 if (m_agentCapacity != 0) 726 if (m_linksetCapacity > 0)
727 config.Set("LinksetPrims", m_linksetCapacity);
728
729 if (m_agentCapacity > 0)
686 config.Set("MaxAgents", m_agentCapacity); 730 config.Set("MaxAgents", m_agentCapacity);
687 731
688 if (ScopeID != UUID.Zero) 732 if (ScopeID != UUID.Zero)
@@ -759,9 +803,15 @@ namespace OpenSim.Framework
759 configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, 803 configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
760 "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true); 804 "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
761 805
806 configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
807 "Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true);
808
762 configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, 809 configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
763 "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true); 810 "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true);
764 811
812 configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
813 "Minimum size for nonphysical prims", m_physPrimMin.ToString(), true);
814
765 configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, 815 configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
766 "Maximum size for physical prims", m_physPrimMax.ToString(), true); 816 "Maximum size for physical prims", m_physPrimMax.ToString(), true);
767 817
@@ -771,6 +821,9 @@ namespace OpenSim.Framework
771 configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, 821 configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
772 "Max objects this sim will hold", m_objectCapacity.ToString(), true); 822 "Max objects this sim will hold", m_objectCapacity.ToString(), true);
773 823
824 configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
825 "Max prims an object will hold", m_linksetCapacity.ToString(), true);
826
774 configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, 827 configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
775 "Max avatars this sim will hold", m_agentCapacity.ToString(), true); 828 "Max avatars this sim will hold", m_agentCapacity.ToString(), true);
776 829
@@ -892,6 +945,9 @@ namespace OpenSim.Framework
892 case "object_capacity": 945 case "object_capacity":
893 m_objectCapacity = (int)configuration_result; 946 m_objectCapacity = (int)configuration_result;
894 break; 947 break;
948 case "linkset_capacity":
949 m_linksetCapacity = (int)configuration_result;
950 break;
895 case "agent_capacity": 951 case "agent_capacity":
896 m_agentCapacity = (int)configuration_result; 952 m_agentCapacity = (int)configuration_result;
897 break; 953 break;
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 2c5e001..48f1c4f 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -53,6 +53,11 @@ namespace OpenSim.Framework.Serialization
53 public const string INVENTORY_PATH = "inventory/"; 53 public const string INVENTORY_PATH = "inventory/";
54 54
55 /// <value> 55 /// <value>
56 /// Path for regions in a multi-region archive
57 /// </value>
58 public const string REGIONS_PATH = "regions/";
59
60 /// <value>
56 /// Path for the prims file 61 /// Path for the prims file
57 /// </value> 62 /// </value>
58 public const string OBJECTS_PATH = "objects/"; 63 public const string OBJECTS_PATH = "objects/";
diff --git a/OpenSim/Framework/Serialization/External/OspResolver.cs b/OpenSim/Framework/Serialization/External/OspResolver.cs
index d31d27c..fa7160f 100644
--- a/OpenSim/Framework/Serialization/External/OspResolver.cs
+++ b/OpenSim/Framework/Serialization/External/OspResolver.cs
@@ -65,9 +65,14 @@ namespace OpenSim.Framework.Serialization
65 65
66 UserAccount account = userService.GetUserAccount(UUID.Zero, userId); 66 UserAccount account = userService.GetUserAccount(UUID.Zero, userId);
67 if (account != null) 67 if (account != null)
68 {
68 return MakeOspa(account.FirstName, account.LastName); 69 return MakeOspa(account.FirstName, account.LastName);
70 }
69// else 71// else
72// {
70// m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId); 73// m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId);
74// System.Console.WriteLine("[OSP RESOLVER]: No user account for {0}", userId);
75// }
71 76
72 return null; 77 return null;
73 } 78 }
@@ -79,10 +84,13 @@ namespace OpenSim.Framework.Serialization
79 /// <returns></returns> 84 /// <returns></returns>
80 public static string MakeOspa(string firstName, string lastName) 85 public static string MakeOspa(string firstName, string lastName)
81 { 86 {
82// m_log.DebugFormat("[OSP RESOLVER]: Making OSPA for {0} {1}", firstName, lastName); 87 string ospa
88 = OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName;
89
90// m_log.DebugFormat("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
91// System.Console.WriteLine("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName);
83 92
84 return 93 return ospa;
85 OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName;
86 } 94 }
87 95
88 /// <summary> 96 /// <summary>
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index cf19002..a8f3a9e 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
96 get { return m_httpServer; } 96 get { return m_httpServer; }
97 } 97 }
98 98
99 /// <summary>
100 /// Holds the non-viewer statistics collection object for this service/server
101 /// </summary>
102 protected IStatsCollector m_stats;
103
104 public BaseOpenSimServer() 99 public BaseOpenSimServer()
105 { 100 {
106 m_startuptime = DateTime.Now; 101 m_startuptime = DateTime.Now;
@@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
177 "show info", 172 "show info",
178 "Show general information about the server", HandleShow); 173 "Show general information about the server", HandleShow);
179 174
180 m_console.Commands.AddCommand("General", false, "show stats",
181 "show stats",
182 "Show statistics", HandleShow);
183
184 m_console.Commands.AddCommand("General", false, "show threads", 175 m_console.Commands.AddCommand("General", false, "show threads",
185 "show threads", 176 "show threads",
186 "Show thread status", HandleShow); 177 "Show thread status", HandleShow);
@@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
226 { 217 {
227 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); 218 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
228 sb.Append(GetUptimeReport()); 219 sb.Append(GetUptimeReport());
229 220 sb.Append(StatsManager.SimExtraStats.Report());
230 if (m_stats != null)
231 {
232 sb.Append(m_stats.Report());
233 }
234
235 sb.Append(Environment.NewLine); 221 sb.Append(Environment.NewLine);
236 sb.Append(GetThreadsReport()); 222 sb.Append(GetThreadsReport());
237 223
@@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
382 { 368 {
383 Notice("set log level [level] - change the console logging level only. For example, off or debug."); 369 Notice("set log level [level] - change the console logging level only. For example, off or debug.");
384 Notice("show info - show server information (e.g. startup path)."); 370 Notice("show info - show server information (e.g. startup path).");
385
386 if (m_stats != null)
387 Notice("show stats - show statistical information for this server");
388
389 Notice("show threads - list tracked threads"); 371 Notice("show threads - list tracked threads");
390 Notice("show uptime - show server startup time and uptime."); 372 Notice("show uptime - show server startup time and uptime.");
391 Notice("show version - show server version."); 373 Notice("show version - show server version.");
@@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
409 ShowInfo(); 391 ShowInfo();
410 break; 392 break;
411 393
412 case "stats":
413 if (m_stats != null)
414 Notice(m_stats.Report());
415 break;
416
417 case "threads": 394 case "threads":
418 Notice(GetThreadsReport()); 395 Notice(GetThreadsReport());
419 break; 396 break;
@@ -604,8 +581,7 @@ namespace OpenSim.Framework.Servers
604 581
605 public string osSecret { 582 public string osSecret {
606 // Secret uuid for the simulator 583 // Secret uuid for the simulator
607 get { return m_osSecret; } 584 get { return m_osSecret; }
608
609 } 585 }
610 586
611 public string StatReport(IOSHttpRequest httpRequest) 587 public string StatReport(IOSHttpRequest httpRequest)
@@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
613 // If we catch a request for "callback", wrap the response in the value for jsonp 589 // If we catch a request for "callback", wrap the response in the value for jsonp
614 if (httpRequest.Query.ContainsKey("callback")) 590 if (httpRequest.Query.ContainsKey("callback"))
615 { 591 {
616 return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; 592 return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
617 } 593 }
618 else 594 else
619 { 595 {
620 return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); 596 return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
621 } 597 }
622 } 598 }
623 599
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 788a0b9..b3e31a6 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -54,8 +54,23 @@ namespace OpenSim.Framework.Servers.HttpServer
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); 55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
56 56
57 /// <summary>
58 /// Gets or sets the debug level.
59 /// </summary>
60 /// <value>
61 /// See MainServer.DebugLevel.
62 /// </value>
57 public int DebugLevel { get; set; } 63 public int DebugLevel { get; set; }
58 64
65 /// <summary>
66 /// Request number for diagnostic purposes.
67 /// </summary>
68 /// <remarks>
69 /// This is an internal number. In some debug situations an external number may also be supplied in the
70 /// opensim-request-id header but we are not currently logging this.
71 /// </remarks>
72 public int RequestNumber { get; private set; }
73
59 private volatile int NotSocketErrors = 0; 74 private volatile int NotSocketErrors = 0;
60 public volatile bool HTTPDRunning = false; 75 public volatile bool HTTPDRunning = false;
61 76
@@ -67,7 +82,7 @@ namespace OpenSim.Framework.Servers.HttpServer
67 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); 82 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
68 protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>(); 83 protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
69 protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); 84 protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
70 protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); 85// protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
71 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = 86 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
72 new Dictionary<string, PollServiceEventArgs>(); 87 new Dictionary<string, PollServiceEventArgs>();
73 88
@@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
245 return new List<string>(m_pollHandlers.Keys); 260 return new List<string>(m_pollHandlers.Keys);
246 } 261 }
247 262
248 // Note that the agent string is provided simply to differentiate 263// // Note that the agent string is provided simply to differentiate
249 // the handlers - it is NOT required to be an actual agent header 264// // the handlers - it is NOT required to be an actual agent header
250 // value. 265// // value.
251 public bool AddAgentHandler(string agent, IHttpAgentHandler handler) 266// public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
252 { 267// {
253 lock (m_agentHandlers) 268// lock (m_agentHandlers)
254 { 269// {
255 if (!m_agentHandlers.ContainsKey(agent)) 270// if (!m_agentHandlers.ContainsKey(agent))
256 { 271// {
257 m_agentHandlers.Add(agent, handler); 272// m_agentHandlers.Add(agent, handler);
258 return true; 273// return true;
259 } 274// }
260 } 275// }
261 276//
262 //must already have a handler for that path so return false 277// //must already have a handler for that path so return false
263 return false; 278// return false;
264 } 279// }
265 280//
266 public List<string> GetAgentHandlerKeys() 281// public List<string> GetAgentHandlerKeys()
267 { 282// {
268 lock (m_agentHandlers) 283// lock (m_agentHandlers)
269 return new List<string>(m_agentHandlers.Keys); 284// return new List<string>(m_agentHandlers.Keys);
270 } 285// }
271 286
272 public bool AddLLSDHandler(string path, LLSDMethod handler) 287 public bool AddLLSDHandler(string path, LLSDMethod handler)
273 { 288 {
@@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
296 311
297 private void OnRequest(object source, RequestEventArgs args) 312 private void OnRequest(object source, RequestEventArgs args)
298 { 313 {
314 RequestNumber++;
315
299 try 316 try
300 { 317 {
301 IHttpClientContext context = (IHttpClientContext)source; 318 IHttpClientContext context = (IHttpClientContext)source;
@@ -406,7 +423,6 @@ namespace OpenSim.Framework.Servers.HttpServer
406 string requestMethod = request.HttpMethod; 423 string requestMethod = request.HttpMethod;
407 string uriString = request.RawUrl; 424 string uriString = request.RawUrl;
408 425
409// string reqnum = "unknown";
410 int requestStartTick = Environment.TickCount; 426 int requestStartTick = Environment.TickCount;
411 427
412 // Will be adjusted later on. 428 // Will be adjusted later on.
@@ -423,22 +439,22 @@ namespace OpenSim.Framework.Servers.HttpServer
423 439
424 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 440 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
425 441
426 // This is the REST agent interface. We require an agent to properly identify 442// // This is the REST agent interface. We require an agent to properly identify
427 // itself. If the REST handler recognizes the prefix it will attempt to 443// // itself. If the REST handler recognizes the prefix it will attempt to
428 // satisfy the request. If it is not recognizable, and no damage has occurred 444// // satisfy the request. If it is not recognizable, and no damage has occurred
429 // the request can be passed through to the other handlers. This is a low 445// // the request can be passed through to the other handlers. This is a low
430 // probability event; if a request is matched it is normally expected to be 446// // probability event; if a request is matched it is normally expected to be
431 // handled 447// // handled
432 IHttpAgentHandler agentHandler; 448// IHttpAgentHandler agentHandler;
433 449//
434 if (TryGetAgentHandler(request, response, out agentHandler)) 450// if (TryGetAgentHandler(request, response, out agentHandler))
435 { 451// {
436 if (HandleAgentRequest(agentHandler, request, response)) 452// if (HandleAgentRequest(agentHandler, request, response))
437 { 453// {
438 requestEndTick = Environment.TickCount; 454// requestEndTick = Environment.TickCount;
439 return; 455// return;
440 } 456// }
441 } 457// }
442 458
443 //response.KeepAlive = true; 459 //response.KeepAlive = true;
444 response.SendChunked = false; 460 response.SendChunked = false;
@@ -450,9 +466,7 @@ namespace OpenSim.Framework.Servers.HttpServer
450 if (TryGetStreamHandler(handlerKey, out requestHandler)) 466 if (TryGetStreamHandler(handlerKey, out requestHandler))
451 { 467 {
452 if (DebugLevel >= 3) 468 if (DebugLevel >= 3)
453 m_log.DebugFormat( 469 LogIncomingToStreamHandler(request, requestHandler);
454 "[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
455 request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
456 470
457 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. 471 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
458 472
@@ -532,8 +546,8 @@ namespace OpenSim.Framework.Servers.HttpServer
532 546
533 if (DebugLevel >= 3) 547 if (DebugLevel >= 3)
534 m_log.DebugFormat( 548 m_log.DebugFormat(
535 "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", 549 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
536 request.ContentType, request.HttpMethod, request.Url.PathAndQuery); 550 RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
537 551
538 buffer = HandleHTTPRequest(request, response); 552 buffer = HandleHTTPRequest(request, response);
539 break; 553 break;
@@ -544,8 +558,8 @@ namespace OpenSim.Framework.Servers.HttpServer
544 558
545 if (DebugLevel >= 3) 559 if (DebugLevel >= 3)
546 m_log.DebugFormat( 560 m_log.DebugFormat(
547 "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", 561 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
548 request.ContentType, request.HttpMethod, request.Url.PathAndQuery); 562 RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
549 563
550 buffer = HandleLLSDRequests(request, response); 564 buffer = HandleLLSDRequests(request, response);
551 break; 565 break;
@@ -564,9 +578,7 @@ namespace OpenSim.Framework.Servers.HttpServer
564 if (DoWeHaveALLSDHandler(request.RawUrl)) 578 if (DoWeHaveALLSDHandler(request.RawUrl))
565 { 579 {
566 if (DebugLevel >= 3) 580 if (DebugLevel >= 3)
567 m_log.DebugFormat( 581 LogIncomingToContentTypeHandler(request);
568 "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
569 request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
570 582
571 buffer = HandleLLSDRequests(request, response); 583 buffer = HandleLLSDRequests(request, response);
572 } 584 }
@@ -574,18 +586,14 @@ namespace OpenSim.Framework.Servers.HttpServer
574 else if (DoWeHaveAHTTPHandler(request.RawUrl)) 586 else if (DoWeHaveAHTTPHandler(request.RawUrl))
575 { 587 {
576 if (DebugLevel >= 3) 588 if (DebugLevel >= 3)
577 m_log.DebugFormat( 589 LogIncomingToContentTypeHandler(request);
578 "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
579 request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
580 590
581 buffer = HandleHTTPRequest(request, response); 591 buffer = HandleHTTPRequest(request, response);
582 } 592 }
583 else 593 else
584 { 594 {
585 if (DebugLevel >= 3) 595 if (DebugLevel >= 3)
586 m_log.DebugFormat( 596 LogIncomingToXmlRpcHandler(request);
587 "[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
588 request.HttpMethod, request.Url.PathAndQuery);
589 597
590 // generic login request. 598 // generic login request.
591 buffer = HandleXmlRpcRequests(request, response); 599 buffer = HandleXmlRpcRequests(request, response);
@@ -629,11 +637,11 @@ namespace OpenSim.Framework.Servers.HttpServer
629 } 637 }
630 catch (IOException e) 638 catch (IOException e)
631 { 639 {
632 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); 640 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
633 } 641 }
634 catch (Exception e) 642 catch (Exception e)
635 { 643 {
636 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); 644 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
637 SendHTML500(response); 645 SendHTML500(response);
638 } 646 }
639 finally 647 finally
@@ -644,17 +652,93 @@ namespace OpenSim.Framework.Servers.HttpServer
644 if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture")) 652 if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
645 { 653 {
646 m_log.InfoFormat( 654 m_log.InfoFormat(
647 "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", 655 "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
656 RequestNumber,
648 requestMethod, 657 requestMethod,
649 uriString, 658 uriString,
650 requestHandler != null ? requestHandler.Name : "", 659 requestHandler != null ? requestHandler.Name : "",
651 requestHandler != null ? requestHandler.Description : "", 660 requestHandler != null ? requestHandler.Description : "",
652 request.RemoteIPEndPoint.ToString(), 661 request.RemoteIPEndPoint,
662 tickdiff);
663 }
664 else if (DebugLevel >= 4)
665 {
666 m_log.DebugFormat(
667 "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
668 RequestNumber,
669 Port,
653 tickdiff); 670 tickdiff);
654 } 671 }
655 } 672 }
656 } 673 }
657 674
675 private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
676 {
677 m_log.DebugFormat(
678 "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
679 RequestNumber,
680 Port,
681 request.HttpMethod,
682 request.Url.PathAndQuery,
683 requestHandler.Name,
684 requestHandler.Description,
685 request.RemoteIPEndPoint);
686
687 if (DebugLevel >= 5)
688 LogIncomingInDetail(request);
689 }
690
691 private void LogIncomingToContentTypeHandler(OSHttpRequest request)
692 {
693 m_log.DebugFormat(
694 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
695 RequestNumber,
696 Port,
697 request.ContentType,
698 request.HttpMethod,
699 request.Url.PathAndQuery,
700 request.RemoteIPEndPoint);
701
702 if (DebugLevel >= 5)
703 LogIncomingInDetail(request);
704 }
705
706 private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
707 {
708 m_log.DebugFormat(
709 "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
710 RequestNumber,
711 Port,
712 request.HttpMethod,
713 request.Url.PathAndQuery,
714 request.RemoteIPEndPoint);
715
716 if (DebugLevel >= 5)
717 LogIncomingInDetail(request);
718 }
719
720 private void LogIncomingInDetail(OSHttpRequest request)
721 {
722 using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8))
723 {
724 string output;
725
726 if (DebugLevel == 5)
727 {
728 const int sampleLength = 80;
729 char[] sampleChars = new char[sampleLength];
730 reader.Read(sampleChars, 0, sampleLength);
731 output = new string(sampleChars);
732 }
733 else
734 {
735 output = reader.ReadToEnd();
736 }
737
738 m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
739 }
740 }
741
658 private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) 742 private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler)
659 { 743 {
660 string bestMatch = null; 744 string bestMatch = null;
@@ -747,24 +831,24 @@ namespace OpenSim.Framework.Servers.HttpServer
747 } 831 }
748 } 832 }
749 833
750 private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) 834// private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
751 { 835// {
752 agentHandler = null; 836// agentHandler = null;
753 837//
754 lock (m_agentHandlers) 838// lock (m_agentHandlers)
755 { 839// {
756 foreach (IHttpAgentHandler handler in m_agentHandlers.Values) 840// foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
757 { 841// {
758 if (handler.Match(request, response)) 842// if (handler.Match(request, response))
759 { 843// {
760 agentHandler = handler; 844// agentHandler = handler;
761 return true; 845// return true;
762 } 846// }
763 } 847// }
764 } 848// }
765 849//
766 return false; 850// return false;
767 } 851// }
768 852
769 /// <summary> 853 /// <summary>
770 /// Try all the registered xmlrpc handlers when an xmlrpc request is received. 854 /// Try all the registered xmlrpc handlers when an xmlrpc request is received.
@@ -1737,21 +1821,21 @@ namespace OpenSim.Framework.Servers.HttpServer
1737 m_pollHandlers.Remove(path); 1821 m_pollHandlers.Remove(path);
1738 } 1822 }
1739 1823
1740 public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) 1824// public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
1741 { 1825// {
1742 lock (m_agentHandlers) 1826// lock (m_agentHandlers)
1743 { 1827// {
1744 IHttpAgentHandler foundHandler; 1828// IHttpAgentHandler foundHandler;
1745 1829//
1746 if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler) 1830// if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
1747 { 1831// {
1748 m_agentHandlers.Remove(agent); 1832// m_agentHandlers.Remove(agent);
1749 return true; 1833// return true;
1750 } 1834// }
1751 } 1835// }
1752 1836//
1753 return false; 1837// return false;
1754 } 1838// }
1755 1839
1756 public void RemoveXmlRPCHandler(string method) 1840 public void RemoveXmlRPCHandler(string method)
1757 { 1841 {
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index db58f6f..0bd3aae 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -41,10 +41,10 @@ namespace OpenSim.Framework.Servers.HttpServer
41 uint Port { get; } 41 uint Port { get; }
42 bool UseSSL { get; } 42 bool UseSSL { get; }
43 43
44 // Note that the agent string is provided simply to differentiate 44// // Note that the agent string is provided simply to differentiate
45 // the handlers - it is NOT required to be an actual agent header 45// // the handlers - it is NOT required to be an actual agent header
46 // value. 46// // value.
47 bool AddAgentHandler(string agent, IHttpAgentHandler handler); 47// bool AddAgentHandler(string agent, IHttpAgentHandler handler);
48 48
49 /// <summary> 49 /// <summary>
50 /// Add a handler for an HTTP request. 50 /// Add a handler for an HTTP request.
@@ -106,13 +106,13 @@ namespace OpenSim.Framework.Servers.HttpServer
106 106
107 bool SetDefaultLLSDHandler(DefaultLLSDMethod handler); 107 bool SetDefaultLLSDHandler(DefaultLLSDMethod handler);
108 108
109 /// <summary> 109// /// <summary>
110 /// Remove the agent if it is registered. 110// /// Remove the agent if it is registered.
111 /// </summary> 111// /// </summary>
112 /// <param name="agent"></param> 112// /// <param name="agent"></param>
113 /// <param name="handler"></param> 113// /// <param name="handler"></param>
114 /// <returns></returns> 114// /// <returns></returns>
115 bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); 115// bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
116 116
117 /// <summary> 117 /// <summary>
118 /// Remove an HTTP handler 118 /// Remove an HTTP handler
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index 8dc0e3a..ae7d515 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Net; 31using System.Net;
32using System.Text;
32using log4net; 33using log4net;
33using OpenSim.Framework; 34using OpenSim.Framework;
34using OpenSim.Framework.Console; 35using OpenSim.Framework.Console;
@@ -47,9 +48,12 @@ namespace OpenSim.Framework.Servers
47 /// Control the printing of certain debug messages. 48 /// Control the printing of certain debug messages.
48 /// </summary> 49 /// </summary>
49 /// <remarks> 50 /// <remarks>
50 /// If DebugLevel >= 1, then short warnings are logged when receiving bad input data. 51 /// If DebugLevel >= 1 then short warnings are logged when receiving bad input data.
51 /// If DebugLevel >= 2, then long warnings are logged when receiving bad input data. 52 /// If DebugLevel >= 2 then long warnings are logged when receiving bad input data.
52 /// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged. 53 /// If DebugLevel >= 3 then short notices about all incoming non-poll HTTP requests are logged.
54 /// If DebugLevel >= 4 then the time taken to fulfill the request is logged.
55 /// If DebugLevel >= 5 then the start of the body of incoming non-poll HTTP requests will be logged.
56 /// If DebugLevel >= 6 then the entire body of incoming non-poll HTTP requests will be logged.
53 /// </remarks> 57 /// </remarks>
54 public static int DebugLevel 58 public static int DebugLevel
55 { 59 {
@@ -101,17 +105,28 @@ namespace OpenSim.Framework.Servers
101 get { return new Dictionary<uint, BaseHttpServer>(m_Servers); } 105 get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
102 } 106 }
103 107
104
105 public static void RegisterHttpConsoleCommands(ICommandConsole console) 108 public static void RegisterHttpConsoleCommands(ICommandConsole console)
106 { 109 {
107 console.Commands.AddCommand( 110 console.Commands.AddCommand(
108 "Debug", false, "debug http", "debug http [<level>]", 111 "Comms", false, "show http-handlers",
109 "Turn on inbound non-poll http request debugging.", 112 "show http-handlers",
110 "If level <= 0, then no extra logging is done.\n" 113 "Show all registered http handlers", HandleShowHttpHandlersCommand);
111 + "If level >= 1, then short warnings are logged when receiving bad input data.\n" 114
112 + "If level >= 2, then long warnings are logged when receiving bad input data.\n" 115 console.Commands.AddCommand(
113 + "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n" 116 "Debug", false, "debug http", "debug http <in|out|all> [<level>]",
114 + "If no level is specified then the current level is returned.", 117 "Turn on http request logging.",
118 "If in or all and\n"
119 + " level <= 0 then no extra logging is done.\n"
120 + " level >= 1 then short warnings are logged when receiving bad input data.\n"
121 + " level >= 2 then long warnings are logged when receiving bad input data.\n"
122 + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
123 + " level >= 4 then the time taken to fulfill the request is logged.\n"
124 + " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
125 + " level >= 6 then the entire incoming data is logged.\n"
126 + " no level is specified then the current level is returned.\n\n"
127 + "If out or all and\n"
128 + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
129 + " level >= 4 then the time taken to fulfill the request is logged.\n",
115 HandleDebugHttpCommand); 130 HandleDebugHttpCommand);
116 } 131 }
117 132
@@ -119,25 +134,120 @@ namespace OpenSim.Framework.Servers
119 /// Turn on some debugging values for OpenSim. 134 /// Turn on some debugging values for OpenSim.
120 /// </summary> 135 /// </summary>
121 /// <param name="args"></param> 136 /// <param name="args"></param>
122 private static void HandleDebugHttpCommand(string module, string[] args) 137 private static void HandleDebugHttpCommand(string module, string[] cmdparams)
123 { 138 {
124 if (args.Length == 3) 139 if (cmdparams.Length < 3)
140 {
141 MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
142 return;
143 }
144
145 bool inReqs = false;
146 bool outReqs = false;
147 bool allReqs = false;
148
149 string subCommand = cmdparams[2];
150
151 if (subCommand.ToLower() == "in")
152 {
153 inReqs = true;
154 }
155 else if (subCommand.ToLower() == "out")
156 {
157 outReqs = true;
158 }
159 else if (subCommand.ToLower() == "all")
160 {
161 allReqs = true;
162 }
163 else
125 { 164 {
165 MainConsole.Instance.Output("You must specify in, out or all");
166 return;
167 }
168
169 if (cmdparams.Length >= 4)
170 {
171 string rawNewDebug = cmdparams[3];
126 int newDebug; 172 int newDebug;
127 if (int.TryParse(args[2], out newDebug)) 173
174 if (!int.TryParse(rawNewDebug, out newDebug))
175 {
176 MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawNewDebug);
177 return;
178 }
179
180 if (newDebug < 0 || newDebug > 6)
181 {
182 MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
183 return;
184 }
185
186 if (allReqs || inReqs)
128 { 187 {
129 MainServer.DebugLevel = newDebug; 188 MainServer.DebugLevel = newDebug;
130 MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug); 189 MainConsole.Instance.OutputFormat("IN debug level set to {0}", newDebug);
190 }
191
192 if (allReqs || outReqs)
193 {
194 WebUtil.DebugLevel = newDebug;
195 MainConsole.Instance.OutputFormat("OUT debug level set to {0}", newDebug);
131 } 196 }
132 } 197 }
133 else if (args.Length == 2) 198 else
134 { 199 {
135 MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel); 200 if (allReqs || inReqs)
201 MainConsole.Instance.OutputFormat("Current IN debug level is {0}", MainServer.DebugLevel);
202
203 if (allReqs || outReqs)
204 MainConsole.Instance.OutputFormat("Current OUT debug level is {0}", WebUtil.DebugLevel);
136 } 205 }
137 else 206 }
207
208 private static void HandleShowHttpHandlersCommand(string module, string[] args)
209 {
210 if (args.Length != 2)
211 {
212 MainConsole.Instance.Output("Usage: show http-handlers");
213 return;
214 }
215
216 StringBuilder handlers = new StringBuilder();
217
218 lock (m_Servers)
138 { 219 {
139 MainConsole.Instance.Output("Usage: debug http 0..3"); 220 foreach (BaseHttpServer httpServer in m_Servers.Values)
221 {
222 handlers.AppendFormat(
223 "Registered HTTP Handlers for server at {0}:{1}\n", httpServer.ListenIPAddress, httpServer.Port);
224
225 handlers.AppendFormat("* XMLRPC:\n");
226 foreach (String s in httpServer.GetXmlRpcHandlerKeys())
227 handlers.AppendFormat("\t{0}\n", s);
228
229 handlers.AppendFormat("* HTTP:\n");
230 List<String> poll = httpServer.GetPollServiceHandlerKeys();
231 foreach (String s in httpServer.GetHTTPHandlerKeys())
232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
233
234// handlers.AppendFormat("* Agent:\n");
235// foreach (String s in httpServer.GetAgentHandlerKeys())
236// handlers.AppendFormat("\t{0}\n", s);
237
238 handlers.AppendFormat("* LLSD:\n");
239 foreach (String s in httpServer.GetLLSDHandlerKeys())
240 handlers.AppendFormat("\t{0}\n", s);
241
242 handlers.AppendFormat("* StreamHandlers ({0}):\n", httpServer.GetStreamHandlerKeys().Count);
243 foreach (String s in httpServer.GetStreamHandlerKeys())
244 handlers.AppendFormat("\t{0}\n", s);
245
246 handlers.Append("\n");
247 }
140 } 248 }
249
250 MainConsole.Instance.Output(handlers.ToString());
141 } 251 }
142 252
143 /// <summary> 253 /// <summary>
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index 016a174..bb094ed 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -29,7 +29,7 @@ namespace OpenSim
29{ 29{
30 public class VersionInfo 30 public class VersionInfo
31 { 31 {
32 private const string VERSION_NUMBER = "0.7.4CM"; 32 private const string VERSION_NUMBER = "0.7.5CM";
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
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 384f716..74551ea 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -546,6 +546,19 @@ namespace OpenSim.Framework
546 } 546 }
547 547
548 /// <summary> 548 /// <summary>
549 /// Determines whether a point is inside a bounding box.
550 /// </summary>
551 /// <param name='v'>/param>
552 /// <param name='min'></param>
553 /// <param name='max'></param>
554 /// <returns></returns>
555 public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
556 {
557 return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
558 && v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
559 }
560
561 /// <summary>
549 /// Are the co-ordinates of the new region visible from the old region? 562 /// Are the co-ordinates of the new region visible from the old region?
550 /// </summary> 563 /// </summary>
551 /// <param name="oldx">Old region x-coord</param> 564 /// <param name="oldx">Old region x-coord</param>
@@ -862,6 +875,12 @@ namespace OpenSim.Framework
862 return Math.Min(Math.Max(x, min), max); 875 return Math.Min(Math.Max(x, min), max);
863 } 876 }
864 877
878 public static Vector3 Clip(Vector3 vec, float min, float max)
879 {
880 return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max),
881 Clip(vec.Z, min, max));
882 }
883
865 /// <summary> 884 /// <summary>
866 /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. 885 /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
867 /// </summary> 886 /// </summary>
@@ -1013,6 +1032,38 @@ namespace OpenSim.Framework
1013 } 1032 }
1014 } 1033 }
1015 1034
1035 /// <summary>
1036 /// Copy data from one stream to another, leaving the read position of both streams at the beginning.
1037 /// </summary>
1038 /// <param name='inputStream'>
1039 /// Input stream. Must be seekable.
1040 /// </param>
1041 /// <exception cref='ArgumentException'>
1042 /// Thrown if the input stream is not seekable.
1043 /// </exception>
1044 public static Stream Copy(Stream inputStream)
1045 {
1046 if (!inputStream.CanSeek)
1047 throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
1048
1049 const int readSize = 256;
1050 byte[] buffer = new byte[readSize];
1051 MemoryStream ms = new MemoryStream();
1052
1053 int count = inputStream.Read(buffer, 0, readSize);
1054
1055 while (count > 0)
1056 {
1057 ms.Write(buffer, 0, count);
1058 count = inputStream.Read(buffer, 0, readSize);
1059 }
1060
1061 ms.Position = 0;
1062 inputStream.Position = 0;
1063
1064 return ms;
1065 }
1066
1016 public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) 1067 public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
1017 { 1068 {
1018 return SendXmlRpcCommand(url, methodName, args); 1069 return SendXmlRpcCommand(url, methodName, args);
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 8094b6d..a03d626 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -54,9 +54,17 @@ namespace OpenSim.Framework
54 MethodBase.GetCurrentMethod().DeclaringType); 54 MethodBase.GetCurrentMethod().DeclaringType);
55 55
56 /// <summary> 56 /// <summary>
57 /// Control the printing of certain debug messages.
58 /// </summary>
59 /// <remarks>
60 /// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
61 /// </remarks>
62 public static int DebugLevel { get; set; }
63
64 /// <summary>
57 /// Request number for diagnostic purposes. 65 /// Request number for diagnostic purposes.
58 /// </summary> 66 /// </summary>
59 public static int RequestNumber = 0; 67 public static int RequestNumber { get; internal set; }
60 68
61 /// <summary> 69 /// <summary>
62 /// this is the header field used to communicate the local request id 70 /// this is the header field used to communicate the local request id
@@ -146,7 +154,11 @@ namespace OpenSim.Framework
146 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) 154 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
147 { 155 {
148 int reqnum = RequestNumber++; 156 int reqnum = RequestNumber++;
149 // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); 157
158 if (DebugLevel >= 3)
159 m_log.DebugFormat(
160 "[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
161 reqnum, method, url, timeout, compressed);
150 162
151 string errorMessage = "unknown error"; 163 string errorMessage = "unknown error";
152 int tickstart = Util.EnvironmentTickCount(); 164 int tickstart = Util.EnvironmentTickCount();
@@ -230,7 +242,7 @@ namespace OpenSim.Framework
230 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 242 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
231 if (tickdiff > LongCallTime) 243 if (tickdiff > LongCallTime)
232 m_log.InfoFormat( 244 m_log.InfoFormat(
233 "[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", 245 "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
234 reqnum, 246 reqnum,
235 method, 247 method,
236 url, 248 url,
@@ -239,10 +251,14 @@ namespace OpenSim.Framework
239 strBuffer != null 251 strBuffer != null
240 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) 252 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
241 : ""); 253 : "");
254 else if (DebugLevel >= 4)
255 m_log.DebugFormat(
256 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
257 reqnum, tickdiff, tickdata);
242 } 258 }
243 259
244 m_log.DebugFormat( 260 m_log.DebugFormat(
245 "[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); 261 "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
246 262
247 return ErrorResponseMap(errorMessage); 263 return ErrorResponseMap(errorMessage);
248 } 264 }
@@ -318,7 +334,11 @@ namespace OpenSim.Framework
318 { 334 {
319 int reqnum = RequestNumber++; 335 int reqnum = RequestNumber++;
320 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; 336 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
321 // m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method); 337
338 if (DebugLevel >= 3)
339 m_log.DebugFormat(
340 "[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
341 reqnum, method, url, timeout);
322 342
323 string errorMessage = "unknown error"; 343 string errorMessage = "unknown error";
324 int tickstart = Util.EnvironmentTickCount(); 344 int tickstart = Util.EnvironmentTickCount();
@@ -381,7 +401,7 @@ namespace OpenSim.Framework
381 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 401 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
382 if (tickdiff > LongCallTime) 402 if (tickdiff > LongCallTime)
383 m_log.InfoFormat( 403 m_log.InfoFormat(
384 "[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", 404 "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
385 reqnum, 405 reqnum,
386 method, 406 method,
387 url, 407 url,
@@ -390,9 +410,13 @@ namespace OpenSim.Framework
390 queryString != null 410 queryString != null
391 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString 411 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
392 : ""); 412 : "");
413 else if (DebugLevel >= 4)
414 m_log.DebugFormat(
415 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
416 reqnum, tickdiff, tickdata);
393 } 417 }
394 418
395 m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage); 419 m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
396 420
397 return ErrorResponseMap(errorMessage); 421 return ErrorResponseMap(errorMessage);
398 } 422 }
@@ -644,7 +668,6 @@ namespace OpenSim.Framework
644 /// <returns></returns> 668 /// <returns></returns>
645 public static string[] GetPreferredImageTypes(string accept) 669 public static string[] GetPreferredImageTypes(string accept)
646 { 670 {
647
648 if (accept == null || accept == string.Empty) 671 if (accept == null || accept == string.Empty)
649 return new string[0]; 672 return new string[0];
650 673
@@ -703,13 +726,15 @@ namespace OpenSim.Framework
703 int maxConnections) 726 int maxConnections)
704 { 727 {
705 int reqnum = WebUtil.RequestNumber++; 728 int reqnum = WebUtil.RequestNumber++;
706 // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); 729
730 if (WebUtil.DebugLevel >= 3)
731 m_log.DebugFormat(
732 "[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
733 reqnum, verb, requestUrl);
707 734
708 int tickstart = Util.EnvironmentTickCount(); 735 int tickstart = Util.EnvironmentTickCount();
709 int tickdata = 0; 736 int tickdata = 0;
710 737
711 // m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
712
713 Type type = typeof(TRequest); 738 Type type = typeof(TRequest);
714 739
715 WebRequest request = WebRequest.Create(requestUrl); 740 WebRequest request = WebRequest.Create(requestUrl);
@@ -866,7 +891,7 @@ namespace OpenSim.Framework
866 } 891 }
867 892
868 m_log.InfoFormat( 893 m_log.InfoFormat(
869 "[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", 894 "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
870 reqnum, 895 reqnum,
871 verb, 896 verb,
872 requestUrl, 897 requestUrl,
@@ -874,6 +899,12 @@ namespace OpenSim.Framework
874 tickdata, 899 tickdata,
875 originalRequest); 900 originalRequest);
876 } 901 }
902 else if (WebUtil.DebugLevel >= 4)
903 {
904 m_log.DebugFormat(
905 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
906 reqnum, tickdiff, tickdata);
907 }
877 } 908 }
878 } 909 }
879 910
@@ -894,7 +925,11 @@ namespace OpenSim.Framework
894 public static string MakeRequest(string verb, string requestUrl, string obj) 925 public static string MakeRequest(string verb, string requestUrl, string obj)
895 { 926 {
896 int reqnum = WebUtil.RequestNumber++; 927 int reqnum = WebUtil.RequestNumber++;
897 // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); 928
929 if (WebUtil.DebugLevel >= 3)
930 m_log.DebugFormat(
931 "[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
932 reqnum, verb, requestUrl);
898 933
899 int tickstart = Util.EnvironmentTickCount(); 934 int tickstart = Util.EnvironmentTickCount();
900 int tickdata = 0; 935 int tickdata = 0;
@@ -979,13 +1014,17 @@ namespace OpenSim.Framework
979 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 1014 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
980 if (tickdiff > WebUtil.LongCallTime) 1015 if (tickdiff > WebUtil.LongCallTime)
981 m_log.InfoFormat( 1016 m_log.InfoFormat(
982 "[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", 1017 "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
983 reqnum, 1018 reqnum,
984 verb, 1019 verb,
985 requestUrl, 1020 requestUrl,
986 tickdiff, 1021 tickdiff,
987 tickdata, 1022 tickdata,
988 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); 1023 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1024 else if (WebUtil.DebugLevel >= 4)
1025 m_log.DebugFormat(
1026 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
1027 reqnum, tickdiff, tickdata);
989 1028
990 return respstring; 1029 return respstring;
991 } 1030 }
@@ -1020,7 +1059,11 @@ namespace OpenSim.Framework
1020 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) 1059 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
1021 { 1060 {
1022 int reqnum = WebUtil.RequestNumber++; 1061 int reqnum = WebUtil.RequestNumber++;
1023 // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); 1062
1063 if (WebUtil.DebugLevel >= 3)
1064 m_log.DebugFormat(
1065 "[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
1066 reqnum, verb, requestUrl);
1024 1067
1025 int tickstart = Util.EnvironmentTickCount(); 1068 int tickstart = Util.EnvironmentTickCount();
1026 int tickdata = 0; 1069 int tickdata = 0;
@@ -1139,7 +1182,7 @@ namespace OpenSim.Framework
1139 } 1182 }
1140 1183
1141 m_log.InfoFormat( 1184 m_log.InfoFormat(
1142 "[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", 1185 "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
1143 reqnum, 1186 reqnum,
1144 verb, 1187 verb,
1145 requestUrl, 1188 requestUrl,
@@ -1147,6 +1190,12 @@ namespace OpenSim.Framework
1147 tickdata, 1190 tickdata,
1148 originalRequest); 1191 originalRequest);
1149 } 1192 }
1193 else if (WebUtil.DebugLevel >= 4)
1194 {
1195 m_log.DebugFormat(
1196 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
1197 reqnum, tickdiff, tickdata);
1198 }
1150 1199
1151 return deserial; 1200 return deserial;
1152 } 1201 }
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 6255515..3d4dce1 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -35,6 +35,7 @@ using System.Text;
35using System.Text.RegularExpressions; 35using System.Text.RegularExpressions;
36using System.Timers; 36using System.Timers;
37using log4net; 37using log4net;
38using NDesk.Options;
38using Nini.Config; 39using Nini.Config;
39using OpenMetaverse; 40using OpenMetaverse;
40using OpenSim.Framework; 41using OpenSim.Framework;
@@ -253,8 +254,14 @@ namespace OpenSim
253 m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); 254 m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
254 255
255 m_console.Commands.AddCommand("Debug", false, "debug scene", 256 m_console.Commands.AddCommand("Debug", false, "debug scene",
256 "debug scene <scripting> <collisions> <physics>", 257 "debug scene active|collisions|physics|scripting|teleport true|false",
257 "Turn on scene debugging", Debug); 258 "Turn on scene debugging.",
259 "If active is false then main scene update and maintenance loops are suspended.\n"
260 + "If collisions is false then collisions with other objects are turned off.\n"
261 + "If physics is false then all physics objects are non-physical.\n"
262 + "If scripting is false then no scripting operations happen.\n"
263 + "If teleport is true then some extra teleport debug information is logged.",
264 Debug);
258 265
259 m_console.Commands.AddCommand("General", false, "change region", 266 m_console.Commands.AddCommand("General", false, "change region",
260 "change region <region name>", 267 "change region <region name>",
@@ -291,7 +298,7 @@ namespace OpenSim
291 298
292 m_console.Commands.AddCommand("Archiving", false, "save oar", 299 m_console.Commands.AddCommand("Archiving", false, "save oar",
293 //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]", 300 //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
294 "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]", 301 "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]",
295 "Save a region's data to an OAR archive.", 302 "Save a region's data to an OAR archive.",
296// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine 303// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
297 "-h|--home=<url> adds the url of the profile service to the saved user information.\n" 304 "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
@@ -301,6 +308,7 @@ namespace OpenSim
301 + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n" 308 + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
302 + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n" 309 + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
303 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n" 310 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
311 + "--all saves all the regions in the simulator, instead of just the current region.\n"
304 + "The OAR path must be a filesystem path." 312 + "The OAR path must be a filesystem path."
305 + " If this is not given then the oar is saved to region.oar in the current directory.", 313 + " If this is not given then the oar is saved to region.oar in the current directory.",
306 SaveOar); 314 SaveOar);
@@ -310,8 +318,11 @@ namespace OpenSim
310 "Change the scale of a named prim", HandleEditScale); 318 "Change the scale of a named prim", HandleEditScale);
311 319
312 m_console.Commands.AddCommand("Users", false, "kick user", 320 m_console.Commands.AddCommand("Users", false, "kick user",
313 "kick user <first> <last> [message]", 321 "kick user <first> <last> [--force] [message]",
314 "Kick a user off the simulator", KickUserCommand); 322 "Kick a user off the simulator",
323 "The --force option will kick the user without any checks to see whether it's already in the process of closing\n"
324 + "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them",
325 KickUserCommand);
315 326
316 m_console.Commands.AddCommand("Users", false, "show users", 327 m_console.Commands.AddCommand("Users", false, "show users",
317 "show users [full]", 328 "show users [full]",
@@ -328,10 +339,6 @@ namespace OpenSim
328 "show circuits", 339 "show circuits",
329 "Show agent circuit data", HandleShow); 340 "Show agent circuit data", HandleShow);
330 341
331 m_console.Commands.AddCommand("Comms", false, "show http-handlers",
332 "show http-handlers",
333 "Show all registered http handlers", HandleShow);
334
335 m_console.Commands.AddCommand("Comms", false, "show pending-objects", 342 m_console.Commands.AddCommand("Comms", false, "show pending-objects",
336 "show pending-objects", 343 "show pending-objects",
337 "Show # of objects on the pending queues of all scene viewers", HandleShow); 344 "Show # of objects on the pending queues of all scene viewers", HandleShow);
@@ -416,6 +423,7 @@ namespace OpenSim
416 { 423 {
417 RunCommandScript(m_shutdownCommandsFile); 424 RunCommandScript(m_shutdownCommandsFile);
418 } 425 }
426
419 base.ShutdownSpecific(); 427 base.ShutdownSpecific();
420 } 428 }
421 429
@@ -453,11 +461,17 @@ namespace OpenSim
453 /// <param name="cmdparams">name of avatar to kick</param> 461 /// <param name="cmdparams">name of avatar to kick</param>
454 private void KickUserCommand(string module, string[] cmdparams) 462 private void KickUserCommand(string module, string[] cmdparams)
455 { 463 {
456 if (cmdparams.Length < 4) 464 bool force = false;
465
466 OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; });
467
468 List<string> mainParams = options.Parse(cmdparams);
469
470 if (mainParams.Count < 4)
457 return; 471 return;
458 472
459 string alert = null; 473 string alert = null;
460 if (cmdparams.Length > 4) 474 if (mainParams.Count > 4)
461 alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4)); 475 alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
462 476
463 IList agents = SceneManager.GetCurrentSceneAvatars(); 477 IList agents = SceneManager.GetCurrentSceneAvatars();
@@ -466,8 +480,8 @@ namespace OpenSim
466 { 480 {
467 RegionInfo regionInfo = presence.Scene.RegionInfo; 481 RegionInfo regionInfo = presence.Scene.RegionInfo;
468 482
469 if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) && 483 if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) &&
470 presence.Lastname.ToLower().Contains(cmdparams[3].ToLower())) 484 presence.Lastname.ToLower().Contains(mainParams[3].ToLower()))
471 { 485 {
472 MainConsole.Instance.Output( 486 MainConsole.Instance.Output(
473 String.Format( 487 String.Format(
@@ -480,7 +494,7 @@ namespace OpenSim
480 else 494 else
481 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n"); 495 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
482 496
483 presence.Scene.IncomingCloseAgent(presence.UUID); 497 presence.Scene.IncomingCloseAgent(presence.UUID, force);
484 } 498 }
485 } 499 }
486 500
@@ -922,7 +936,8 @@ namespace OpenSim
922 } 936 }
923 else 937 else
924 { 938 {
925 MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false"); 939 MainConsole.Instance.Output(
940 "Usage: debug scene active|scripting|collisions|physics|teleport true|false");
926 } 941 }
927 942
928 break; 943 break;
@@ -1002,33 +1017,6 @@ namespace OpenSim
1002 HandleShowCircuits(); 1017 HandleShowCircuits();
1003 break; 1018 break;
1004 1019
1005 case "http-handlers":
1006 System.Text.StringBuilder handlers = new System.Text.StringBuilder("Registered HTTP Handlers:\n");
1007
1008 handlers.AppendFormat("* XMLRPC:\n");
1009 foreach (String s in HttpServer.GetXmlRpcHandlerKeys())
1010 handlers.AppendFormat("\t{0}\n", s);
1011
1012 handlers.AppendFormat("* HTTP:\n");
1013 List<String> poll = HttpServer.GetPollServiceHandlerKeys();
1014 foreach (String s in HttpServer.GetHTTPHandlerKeys())
1015 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
1016
1017 handlers.AppendFormat("* Agent:\n");
1018 foreach (String s in HttpServer.GetAgentHandlerKeys())
1019 handlers.AppendFormat("\t{0}\n", s);
1020
1021 handlers.AppendFormat("* LLSD:\n");
1022 foreach (String s in HttpServer.GetLLSDHandlerKeys())
1023 handlers.AppendFormat("\t{0}\n", s);
1024
1025 handlers.AppendFormat("* StreamHandlers ({0}):\n", HttpServer.GetStreamHandlerKeys().Count);
1026 foreach (String s in HttpServer.GetStreamHandlerKeys())
1027 handlers.AppendFormat("\t{0}\n", s);
1028
1029 MainConsole.Instance.Output(handlers.ToString());
1030 break;
1031
1032 case "modules": 1020 case "modules":
1033 MainConsole.Instance.Output("The currently loaded shared modules are:"); 1021 MainConsole.Instance.Output("The currently loaded shared modules are:");
1034 foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules) 1022 foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules)
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index d107b7a..b410a0e 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -232,8 +232,6 @@ namespace OpenSim
232 232
233 base.StartupSpecific(); 233 base.StartupSpecific();
234 234
235 m_stats = StatsManager.SimExtraStats;
236
237 // Create a ModuleLoader instance 235 // Create a ModuleLoader instance
238 m_moduleLoader = new ModuleLoader(m_config.Source); 236 m_moduleLoader = new ModuleLoader(m_config.Source);
239 237
@@ -249,51 +247,51 @@ namespace OpenSim
249 plugin.PostInitialise(); 247 plugin.PostInitialise();
250 } 248 }
251 249
252 AddPluginCommands(); 250 if (m_console != null)
251 {
252 StatsManager.RegisterConsoleCommands(m_console);
253 AddPluginCommands(m_console);
254 }
253 } 255 }
254 256
255 protected virtual void AddPluginCommands() 257 protected virtual void AddPluginCommands(CommandConsole console)
256 { 258 {
257 // If console exists add plugin commands. 259 List<string> topics = GetHelpTopics();
258 if (m_console != null)
259 {
260 List<string> topics = GetHelpTopics();
261 260
262 foreach (string topic in topics) 261 foreach (string topic in topics)
263 { 262 {
264 string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1); 263 string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
265 264
266 // This is a hack to allow the user to enter the help command in upper or lowercase. This will go 265 // This is a hack to allow the user to enter the help command in upper or lowercase. This will go
267 // away at some point. 266 // away at some point.
268 m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic, 267 console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
269 "help " + capitalizedTopic, 268 "help " + capitalizedTopic,
270 "Get help on plugin command '" + topic + "'", 269 "Get help on plugin command '" + topic + "'",
271 HandleCommanderHelp); 270 HandleCommanderHelp);
272 m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic, 271 console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
273 "help " + capitalizedTopic, 272 "help " + capitalizedTopic,
274 "Get help on plugin command '" + topic + "'", 273 "Get help on plugin command '" + topic + "'",
275 HandleCommanderHelp); 274 HandleCommanderHelp);
276 275
277 ICommander commander = null; 276 ICommander commander = null;
278 277
279 Scene s = SceneManager.CurrentOrFirstScene; 278 Scene s = SceneManager.CurrentOrFirstScene;
280 279
281 if (s != null && s.GetCommanders() != null) 280 if (s != null && s.GetCommanders() != null)
282 { 281 {
283 if (s.GetCommanders().ContainsKey(topic)) 282 if (s.GetCommanders().ContainsKey(topic))
284 commander = s.GetCommanders()[topic]; 283 commander = s.GetCommanders()[topic];
285 } 284 }
286 285
287 if (commander == null) 286 if (commander == null)
288 continue; 287 continue;
289 288
290 foreach (string command in commander.Commands.Keys) 289 foreach (string command in commander.Commands.Keys)
291 { 290 {
292 m_console.Commands.AddCommand(capitalizedTopic, false, 291 console.Commands.AddCommand(capitalizedTopic, false,
293 topic + " " + command, 292 topic + " " + command,
294 topic + " " + commander.Commands[command].ShortHelp(), 293 topic + " " + commander.Commands[command].ShortHelp(),
295 String.Empty, HandleCommanderCommand); 294 String.Empty, HandleCommanderCommand);
296 }
297 } 295 }
298 } 296 }
299 } 297 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index c705f10..f509d94 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -241,8 +241,8 @@ namespace OpenSim.Region.ClientStack.Linden
241 m_HostCapsObj.RegisterHandler( 241 m_HostCapsObj.RegisterHandler(
242 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); 242 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
243 243
244 m_log.DebugFormat( 244// m_log.DebugFormat(
245 "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); 245// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
246 246
247 //m_capsHandlers["MapLayer"] = 247 //m_capsHandlers["MapLayer"] =
248 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 248 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
@@ -337,11 +337,12 @@ namespace OpenSim.Region.ClientStack.Linden
337 public string SeedCapRequest(string request, string path, string param, 337 public string SeedCapRequest(string request, string path, string param,
338 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 338 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
339 { 339 {
340// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); 340 m_log.DebugFormat(
341 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
341 342
342 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 343 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
343 { 344 {
344 m_log.DebugFormat( 345 m_log.WarnFormat(
345 "[CAPS]: Unauthorized CAPS client {0} from {1}", 346 "[CAPS]: Unauthorized CAPS client {0} from {1}",
346 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint); 347 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
347 348
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index e113c60..5bbdce8 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
94 94
95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); 95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
96 96
97 scene.EventManager.OnNewClient += OnNewClient; 97// scene.EventManager.OnNewClient += OnNewClient;
98 98
99 // TODO: Leaving these open, or closing them when we 99 // TODO: Leaving these open, or closing them when we
100 // become a child is incorrect. It messes up TP in a big 100 // become a child is incorrect. It messes up TP in a big
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 // circuit is there. 102 // circuit is there.
103 103
104 scene.EventManager.OnClientClosed += ClientClosed; 104 scene.EventManager.OnClientClosed += ClientClosed;
105
105 scene.EventManager.OnMakeChildAgent += MakeChildAgent; 106 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
106 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 107 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
107 108
@@ -110,10 +111,10 @@ namespace OpenSim.Region.ClientStack.Linden
110 false, 111 false,
111 "debug eq", 112 "debug eq",
112 "debug eq [0|1|2]", 113 "debug eq [0|1|2]",
113 "Turn on event queue debugging" 114 "Turn on event queue debugging\n"
114 + "<= 0 - turns off all event queue logging" 115 + " <= 0 - turns off all event queue logging\n"
115 + ">= 1 - turns on outgoing event logging" 116 + " >= 1 - turns on outgoing event logging\n"
116 + ">= 2 - turns on poll notification", 117 + " >= 2 - turns on poll notification",
117 HandleDebugEq); 118 HandleDebugEq);
118 } 119 }
119 else 120 else
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
226 227
227 #endregion 228 #endregion
228 229
229 private void OnNewClient(IClientAPI client)
230 {
231 //client.OnLogout += ClientClosed;
232 }
233
234// private void ClientClosed(IClientAPI client)
235// {
236// ClientClosed(client.AgentId);
237// }
238
239 private void ClientClosed(UUID agentID, Scene scene) 230 private void ClientClosed(UUID agentID, Scene scene)
240 { 231 {
241// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 232// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index cd70410..d604cf6 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
94 UUID spId = TestHelpers.ParseTail(0x1); 94 UUID spId = TestHelpers.ParseTail(0x1);
95 95
96 SceneHelpers.AddScenePresence(m_scene, spId); 96 SceneHelpers.AddScenePresence(m_scene, spId);
97 m_scene.IncomingCloseAgent(spId); 97 m_scene.IncomingCloseAgent(spId, false);
98 98
99 // TODO: Add more assertions for the other aspects of event queues 99 // TODO: Add more assertions for the other aspects of event queues
100 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); 100 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 413536d..bac71b0 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -109,7 +109,7 @@ namespace OpenSim.Region.ClientStack.Linden
109 109
110 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
111 111
112 m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 112// m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
113 caps.RegisterHandler( 113 caps.RegisterHandler(
114 "SimConsoleAsync", 114 "SimConsoleAsync",
115 new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene)); 115 new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ee28914..7686b94 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
48using Timer = System.Timers.Timer; 48using Timer = System.Timers.Timer;
49using AssetLandmark = OpenSim.Framework.AssetLandmark; 49using AssetLandmark = OpenSim.Framework.AssetLandmark;
50using RegionFlags = OpenMetaverse.RegionFlags;
50using Nini.Config; 51using Nini.Config;
51 52
52using System.IO; 53using System.IO;
@@ -509,19 +510,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
509 /// </summary> 510 /// </summary>
510 public void Close() 511 public void Close()
511 { 512 {
512 Close(true); 513 Close(true, false);
513 } 514 }
514 515
515 /// <summary> 516 public void Close(bool sendStop, bool force)
516 /// Shut down the client view
517 /// </summary>
518 public void Close(bool sendStop)
519 { 517 {
520 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 518 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
521 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 519 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
522 lock (CloseSyncLock) 520 lock (CloseSyncLock)
523 { 521 {
524 if (!IsActive) 522 // We still perform a force close inside the sync lock since this is intended to attempt close where
523 // there is some unidentified connection problem, not where we have issues due to deadlock
524 if (!IsActive && !force)
525 return; 525 return;
526 526
527 IsActive = false; 527 IsActive = false;
@@ -3984,7 +3984,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3984 { 3984 {
3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3986 3986
3987 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3987 ImprovedTerseObjectUpdatePacket packet
3988 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3988 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3989 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3989 packet.RegionData.TimeDilation = timeDilation; 3990 packet.RegionData.TimeDilation = timeDilation;
3990 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3991 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4029,7 +4030,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4029 { 4030 {
4030 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 4031 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4031 4032
4032 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 4033 ImprovedTerseObjectUpdatePacket packet
4034 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4035 PacketType.ImprovedTerseObjectUpdate);
4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4036 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4034 packet.RegionData.TimeDilation = timeDilation; 4037 packet.RegionData.TimeDilation = timeDilation;
4035 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4038 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4037,7 +4040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4037 for (int i = 0; i < blocks.Count; i++) 4040 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i]; 4041 packet.ObjectData[i] = blocks[i];
4039 4042
4040 OutPacket(packet, ThrottleOutPacketType.Task, true); 4043 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4041 } 4044 }
4042 4045
4043 #endregion Packet Sending 4046 #endregion Packet Sending
@@ -4534,7 +4537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4534 { 4537 {
4535 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock(); 4538 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4536 } 4539 }
4537 j = 0; 4540 j = 0;
4538 4541
4539 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 4542 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4540 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; 4543 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
@@ -5038,7 +5041,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5038 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 5041 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5039 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; 5042 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5040 5043
5041 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); 5044 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5045 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5046
5042 block.Data = data; 5047 block.Data = data;
5043 5048
5044 if (textureEntry != null && textureEntry.Length > 0) 5049 if (textureEntry != null && textureEntry.Length > 0)
@@ -5963,7 +5968,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5963 msgpack.MessageBlock.ID, 5968 msgpack.MessageBlock.ID,
5964 msgpack.MessageBlock.Offline != 0 ? true : false, 5969 msgpack.MessageBlock.Offline != 0 ? true : false,
5965 msgpack.MessageBlock.Position, 5970 msgpack.MessageBlock.Position,
5966 msgpack.MessageBlock.BinaryBucket); 5971 msgpack.MessageBlock.BinaryBucket,
5972 true);
5967 5973
5968 handlerInstantMessage(this, im); 5974 handlerInstantMessage(this, im);
5969 } 5975 }
@@ -9245,7 +9251,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9245 } 9251 }
9246 #endregion 9252 #endregion
9247 9253
9248 switch (Utils.BytesToString(messagePacket.MethodData.Method)) 9254 string method = Utils.BytesToString(messagePacket.MethodData.Method);
9255
9256 switch (method)
9249 { 9257 {
9250 case "getinfo": 9258 case "getinfo":
9251 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 9259 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9561,7 +9569,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9561 return true; 9569 return true;
9562 9570
9563 default: 9571 default:
9564 m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); 9572 m_log.WarnFormat(
9573 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
9574 method, Name, Scene.Name);
9575
9576 for (int i = 0; i < messagePacket.ParamList.Length; i++)
9577 {
9578 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
9579 string data = (string)Utils.BytesToString(block.Parameter);
9580 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
9581 }
9582
9565 return true; 9583 return true;
9566 } 9584 }
9567 9585
@@ -11949,7 +11967,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11949 logPacket = false; 11967 logPacket = false;
11950 11968
11951 if (DebugPacketLevel <= 50 11969 if (DebugPacketLevel <= 50
11952 & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 11970 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
11953 logPacket = false; 11971 logPacket = false;
11954 11972
11955 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) 11973 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -12193,7 +12211,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12193 { 12211 {
12194 Kick(reason); 12212 Kick(reason);
12195 Thread.Sleep(1000); 12213 Thread.Sleep(1000);
12196 Close(); 12214 Disconnect();
12197 } 12215 }
12198 12216
12199 public void Disconnect() 12217 public void Disconnect()
@@ -12481,7 +12499,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12481 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12499 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12482 12500
12483 12501
12484 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 12502 ImprovedTerseObjectUpdatePacket packet
12503 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12504 PacketType.ImprovedTerseObjectUpdate);
12505
12485 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 12506 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12486 packet.RegionData.TimeDilation = timeDilation; 12507 packet.RegionData.TimeDilation = timeDilation;
12487 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 12508 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index d6513c5..7820caf 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -37,6 +37,7 @@ using log4net;
37using Nini.Config; 37using Nini.Config;
38using OpenMetaverse.Packets; 38using OpenMetaverse.Packets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Console;
40using OpenSim.Framework.Monitoring; 41using OpenSim.Framework.Monitoring;
41using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
42using OpenMetaverse; 43using OpenMetaverse;
@@ -100,9 +101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 101
101 /// <summary>The measured resolution of Environment.TickCount</summary> 102 /// <summary>The measured resolution of Environment.TickCount</summary>
102 public readonly float TickCountResolution; 103 public readonly float TickCountResolution;
104
103 /// <summary>Number of prim updates to put on the queue each time the 105 /// <summary>Number of prim updates to put on the queue each time the
104 /// OnQueueEmpty event is triggered for updates</summary> 106 /// OnQueueEmpty event is triggered for updates</summary>
105 public readonly int PrimUpdatesPerCallback; 107 public readonly int PrimUpdatesPerCallback;
108
106 /// <summary>Number of texture packets to put on the queue each time the 109 /// <summary>Number of texture packets to put on the queue each time the
107 /// OnQueueEmpty event is triggered for textures</summary> 110 /// OnQueueEmpty event is triggered for textures</summary>
108 public readonly int TextureSendLimit; 111 public readonly int TextureSendLimit;
@@ -124,28 +127,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
124 127
125 /// <summary>Manages authentication for agent circuits</summary> 128 /// <summary>Manages authentication for agent circuits</summary>
126 private AgentCircuitManager m_circuitManager; 129 private AgentCircuitManager m_circuitManager;
130
127 /// <summary>Reference to the scene this UDP server is attached to</summary> 131 /// <summary>Reference to the scene this UDP server is attached to</summary>
128 protected Scene m_scene; 132 protected Scene m_scene;
133
129 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 134 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
130 private Location m_location; 135 private Location m_location;
136
131 /// <summary>The size of the receive buffer for the UDP socket. This value 137 /// <summary>The size of the receive buffer for the UDP socket. This value
132 /// is passed up to the operating system and used in the system networking 138 /// is passed up to the operating system and used in the system networking
133 /// stack. Use zero to leave this value as the default</summary> 139 /// stack. Use zero to leave this value as the default</summary>
134 private int m_recvBufferSize; 140 private int m_recvBufferSize;
141
135 /// <summary>Flag to process packets asynchronously or synchronously</summary> 142 /// <summary>Flag to process packets asynchronously or synchronously</summary>
136 private bool m_asyncPacketHandling; 143 private bool m_asyncPacketHandling;
144
137 /// <summary>Tracks whether or not a packet was sent each round so we know 145 /// <summary>Tracks whether or not a packet was sent each round so we know
138 /// whether or not to sleep</summary> 146 /// whether or not to sleep</summary>
139 private bool m_packetSent; 147 private bool m_packetSent;
140 148
141 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 149 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
142 private int m_elapsedMSSinceLastStatReport = 0; 150 private int m_elapsedMSSinceLastStatReport = 0;
151
143 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 152 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
144 private int m_tickLastOutgoingPacketHandler; 153 private int m_tickLastOutgoingPacketHandler;
154
145 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 155 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
146 private int m_elapsedMSOutgoingPacketHandler; 156 private int m_elapsedMSOutgoingPacketHandler;
157
147 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 158 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
148 private int m_elapsed100MSOutgoingPacketHandler; 159 private int m_elapsed100MSOutgoingPacketHandler;
160
149 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 161 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
150 private int m_elapsed500MSOutgoingPacketHandler; 162 private int m_elapsed500MSOutgoingPacketHandler;
151 163
@@ -180,7 +192,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
180 /// </summary> 192 /// </summary>
181 private IClientAPI m_currentIncomingClient; 193 private IClientAPI m_currentIncomingClient;
182 194
183 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 195 public LLUDPServer(
196 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
197 IConfigSource configSource, AgentCircuitManager circuitManager)
184 : base(listenIP, (int)port) 198 : base(listenIP, (int)port)
185 { 199 {
186 #region Environment.TickCount Measurement 200 #region Environment.TickCount Measurement
@@ -227,6 +241,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
227 m_pausedAckTimeout = 1000 * 300; // 5 minutes 241 m_pausedAckTimeout = 1000 * 300; // 5 minutes
228 } 242 }
229 243
244 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
245 // However, there is no harm in temporarily doing it multiple times.
246 IConfig packetConfig = configSource.Configs["PacketPool"];
247 if (packetConfig != null)
248 {
249 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
250 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
251 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
252 }
253
230 #region BinaryStats 254 #region BinaryStats
231 config = configSource.Configs["Statistics.Binary"]; 255 config = configSource.Configs["Statistics.Binary"];
232 m_shouldCollectStats = false; 256 m_shouldCollectStats = false;
@@ -258,16 +282,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
258 282
259 public void Start() 283 public void Start()
260 { 284 {
261 if (m_scene == null) 285 StartInbound();
262 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 286 StartOutbound();
287
288 m_elapsedMSSinceLastStatReport = Environment.TickCount;
289 }
263 290
291 private void StartInbound()
292 {
264 m_log.InfoFormat( 293 m_log.InfoFormat(
265 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", 294 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
266 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 295 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
267 296
268 base.Start(m_recvBufferSize, m_asyncPacketHandling); 297 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
269 298
270 // Start the packet processing threads 299 // This thread will process the packets received that are placed on the packetInbox
271 Watchdog.StartThread( 300 Watchdog.StartThread(
272 IncomingPacketHandler, 301 IncomingPacketHandler,
273 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 302 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -276,7 +305,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
276 true, 305 true,
277 GetWatchdogIncomingAlarmData, 306 GetWatchdogIncomingAlarmData,
278 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 307 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
308 }
309
310 private new void StartOutbound()
311 {
312 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
313
314 base.StartOutbound();
279 315
316 // This thread will process the packets received that are placed on the packetInbox
280 Watchdog.StartThread( 317 Watchdog.StartThread(
281 OutgoingPacketHandler, 318 OutgoingPacketHandler,
282 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), 319 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -285,8 +322,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 true, 322 true,
286 GetWatchdogOutgoingAlarmData, 323 GetWatchdogOutgoingAlarmData,
287 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 324 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
325 }
288 326
289 m_elapsedMSSinceLastStatReport = Environment.TickCount; 327 public void Stop()
328 {
329 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
330 base.StopOutbound();
331 base.StopInbound();
290 } 332 }
291 333
292 /// <summary> 334 /// <summary>
@@ -311,12 +353,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); 353 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
312 } 354 }
313 355
314 public new void Stop()
315 {
316 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
317 base.Stop();
318 }
319
320 public void AddScene(IScene scene) 356 public void AddScene(IScene scene)
321 { 357 {
322 if (m_scene != null) 358 if (m_scene != null)
@@ -333,6 +369,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 369
334 m_scene = (Scene)scene; 370 m_scene = (Scene)scene;
335 m_location = new Location(m_scene.RegionInfo.RegionHandle); 371 m_location = new Location(m_scene.RegionInfo.RegionHandle);
372
373 MainConsole.Instance.Commands.AddCommand(
374 "Debug",
375 false,
376 "debug lludp start",
377 "debug lludp start <in|out|all>",
378 "Control LLUDP packet processing.",
379 "No effect if packet processing has already started.\n"
380 + "in - start inbound processing.\n"
381 + "out - start outbound processing.\n"
382 + "all - start in and outbound processing.\n",
383 HandleStartCommand);
384
385 MainConsole.Instance.Commands.AddCommand(
386 "Debug",
387 false,
388 "debug lludp stop",
389 "debug lludp stop <in|out|all>",
390 "Stop LLUDP packet processing.",
391 "No effect if packet processing has already stopped.\n"
392 + "in - stop inbound processing.\n"
393 + "out - stop outbound processing.\n"
394 + "all - stop in and outbound processing.\n",
395 HandleStopCommand);
396
397 MainConsole.Instance.Commands.AddCommand(
398 "Debug",
399 false,
400 "debug lludp status",
401 "debug lludp status",
402 "Return status of LLUDP packet processing.",
403 HandleStatusCommand);
404 }
405
406 private void HandleStartCommand(string module, string[] args)
407 {
408 if (args.Length != 4)
409 {
410 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
411 return;
412 }
413
414 string subCommand = args[3];
415
416 if (subCommand == "in" || subCommand == "all")
417 StartInbound();
418
419 if (subCommand == "out" || subCommand == "all")
420 StartOutbound();
421 }
422
423 private void HandleStopCommand(string module, string[] args)
424 {
425 if (args.Length != 4)
426 {
427 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
428 return;
429 }
430
431 string subCommand = args[3];
432
433 if (subCommand == "in" || subCommand == "all")
434 StopInbound();
435
436 if (subCommand == "out" || subCommand == "all")
437 StopOutbound();
438 }
439
440 private void HandleStatusCommand(string module, string[] args)
441 {
442 MainConsole.Instance.OutputFormat(
443 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
444
445 MainConsole.Instance.OutputFormat(
446 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
336 } 447 }
337 448
338 public bool HandlesRegion(Location x) 449 public bool HandlesRegion(Location x)
@@ -416,6 +527,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 byte[] data = packet.ToBytes(); 527 byte[] data = packet.ToBytes();
417 SendPacketData(udpClient, data, packet.Type, category, method); 528 SendPacketData(udpClient, data, packet.Type, category, method);
418 } 529 }
530
531 PacketPool.Instance.ReturnPacket(packet);
419 } 532 }
420 533
421 /// <summary> 534 /// <summary>
@@ -700,7 +813,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 LLUDPClient udpClient = null; 813 LLUDPClient udpClient = null;
701 Packet packet = null; 814 Packet packet = null;
702 int packetEnd = buffer.DataLength - 1; 815 int packetEnd = buffer.DataLength - 1;
703 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 816 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
704 817
705 #region Decoding 818 #region Decoding
706 819
@@ -710,7 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 823// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
711// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 824// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
712 825
713 return; // Drop undersizd packet 826 return; // Drop undersized packet
714 } 827 }
715 828
716 int headerLen = 7; 829 int headerLen = 7;
@@ -733,7 +846,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
733 846
734 try 847 try
735 { 848 {
736 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 849// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
850// // Only allocate a buffer for zerodecoding if the packet is zerocoded
851// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
852 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
853 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
854 // bytes are copied out).
855 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
737 // Only allocate a buffer for zerodecoding if the packet is zerocoded 856 // Only allocate a buffer for zerodecoding if the packet is zerocoded
738 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 857 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
739 } 858 }
@@ -748,11 +867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
748 867
749 return; // Drop short packet 868 return; // Drop short packet
750 } 869 }
751 catch(Exception e) 870 catch (Exception e)
752 { 871 {
753 if (m_malformedCount < 100) 872 if (m_malformedCount < 100)
754 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 873 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
874
755 m_malformedCount++; 875 m_malformedCount++;
876
756 if ((m_malformedCount % 100000) == 0) 877 if ((m_malformedCount % 100000) == 0)
757 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); 878 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
758 } 879 }
@@ -772,7 +893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
772 893
773 // If there is already a client for this endpoint, don't process UseCircuitCode 894 // If there is already a client for this endpoint, don't process UseCircuitCode
774 IClientAPI client = null; 895 IClientAPI client = null;
775 if (!m_scene.TryGetClient(address, out client)) 896 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
776 { 897 {
777 // UseCircuitCode handling 898 // UseCircuitCode handling
778 if (packet.Type == PacketType.UseCircuitCode) 899 if (packet.Type == PacketType.UseCircuitCode)
@@ -780,13 +901,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
780 // And if there is a UseCircuitCode pending, also drop it 901 // And if there is a UseCircuitCode pending, also drop it
781 lock (m_pendingCache) 902 lock (m_pendingCache)
782 { 903 {
783 if (m_pendingCache.Contains(address)) 904 if (m_pendingCache.Contains(endPoint))
784 return; 905 return;
785 906
786 m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); 907 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
787 } 908 }
788 909
789 object[] array = new object[] { buffer, packet }; 910 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
911 // buffer.
912 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
790 913
791 Util.FireAndForget(HandleUseCircuitCode, array); 914 Util.FireAndForget(HandleUseCircuitCode, array);
792 915
@@ -798,7 +921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
798 lock (m_pendingCache) 921 lock (m_pendingCache)
799 { 922 {
800 Queue<UDPPacketBuffer> queue; 923 Queue<UDPPacketBuffer> queue;
801 if (m_pendingCache.TryGetValue(address, out queue)) 924 if (m_pendingCache.TryGetValue(endPoint, out queue))
802 { 925 {
803 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); 926 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
804 queue.Enqueue(buffer); 927 queue.Enqueue(buffer);
@@ -1013,21 +1136,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1013 1136
1014 private void HandleUseCircuitCode(object o) 1137 private void HandleUseCircuitCode(object o)
1015 { 1138 {
1016 IPEndPoint remoteEndPoint = null; 1139 IPEndPoint endPoint = null;
1017 IClientAPI client = null; 1140 IClientAPI client = null;
1018 1141
1019 try 1142 try
1020 { 1143 {
1021 // DateTime startTime = DateTime.Now; 1144 // DateTime startTime = DateTime.Now;
1022 object[] array = (object[])o; 1145 object[] array = (object[])o;
1023 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1146 endPoint = (IPEndPoint)array[0];
1024 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1147 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1025 1148
1026 m_log.DebugFormat( 1149 m_log.DebugFormat(
1027 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1150 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1028 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1151 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1029
1030 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1031 1152
1032 AuthenticateResponse sessionInfo; 1153 AuthenticateResponse sessionInfo;
1033 if (IsClientAuthorized(uccp, out sessionInfo)) 1154 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1038,13 +1159,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1038 uccp.CircuitCode.Code, 1159 uccp.CircuitCode.Code,
1039 uccp.CircuitCode.ID, 1160 uccp.CircuitCode.ID,
1040 uccp.CircuitCode.SessionID, 1161 uccp.CircuitCode.SessionID,
1041 remoteEndPoint, 1162 endPoint,
1042 sessionInfo); 1163 sessionInfo);
1043 1164
1044 // Send ack straight away to let the viewer know that the connection is active. 1165 // Send ack straight away to let the viewer know that the connection is active.
1045 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1166 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1046 // circuit code to the existing child agent. This is not particularly obvious. 1167 // circuit code to the existing child agent. This is not particularly obvious.
1047 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1168 SendAckImmediate(endPoint, uccp.Header.Sequence);
1048 1169
1049 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1170 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1050 if (client != null) 1171 if (client != null)
@@ -1058,12 +1179,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 1179
1059 lock (m_pendingCache) 1180 lock (m_pendingCache)
1060 { 1181 {
1061 if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) 1182 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1062 { 1183 {
1063 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1184 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1064 return; 1185 return;
1065 } 1186 }
1066 m_pendingCache.Remove(remoteEndPoint); 1187 m_pendingCache.Remove(endPoint);
1067 } 1188 }
1068 1189
1069 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1190 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@@ -1081,9 +1202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 // Don't create clients for unauthorized requesters. 1202 // Don't create clients for unauthorized requesters.
1082 m_log.WarnFormat( 1203 m_log.WarnFormat(
1083 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1204 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1084 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1205 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1085 lock (m_pendingCache) 1206 lock (m_pendingCache)
1086 m_pendingCache.Remove(remoteEndPoint); 1207 m_pendingCache.Remove(endPoint);
1087 } 1208 }
1088 1209
1089 // m_log.DebugFormat( 1210 // m_log.DebugFormat(
@@ -1095,7 +1216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1095 { 1216 {
1096 m_log.ErrorFormat( 1217 m_log.ErrorFormat(
1097 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1218 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1098 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1219 endPoint != null ? endPoint.ToString() : "n/a",
1099 client != null ? client.Name : "unknown", 1220 client != null ? client.Name : "unknown",
1100 client != null ? client.AgentId.ToString() : "unknown", 1221 client != null ? client.AgentId.ToString() : "unknown",
1101 e.Message, 1222 e.Message,
@@ -1160,20 +1281,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1160 { 1281 {
1161 IClientAPI client = null; 1282 IClientAPI client = null;
1162 1283
1163 // In priciple there shouldn't be more than one thread here, ever. 1284 // We currently synchronize this code across the whole scene to avoid issues such as
1164 // But in case that happens, we need to synchronize this piece of code 1285 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1165 // because it's too important 1286 // consistently, this lock could probably be removed.
1166 lock (this) 1287 lock (this)
1167 { 1288 {
1168 if (!m_scene.TryGetClient(agentID, out client)) 1289 if (!m_scene.TryGetClient(agentID, out client))
1169 { 1290 {
1170 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1291 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1171 1292
1172 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1293 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1173 client.OnLogout += LogoutHandler; 1294 client.OnLogout += LogoutHandler;
1174 1295
1175 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1296 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1176 1297
1177 client.Start(); 1298 client.Start();
1178 } 1299 }
1179 } 1300 }
@@ -1212,7 +1333,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1212 // on to en-US to avoid number parsing issues 1333 // on to en-US to avoid number parsing issues
1213 Culture.SetCurrentCulture(); 1334 Culture.SetCurrentCulture();
1214 1335
1215 while (base.IsRunning) 1336 while (base.IsRunningInbound)
1216 { 1337 {
1217 m_scene.ThreadAlive(1); 1338 m_scene.ThreadAlive(1);
1218 try 1339 try
@@ -1255,7 +1376,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1255 // Action generic every round 1376 // Action generic every round
1256 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1377 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1257 1378
1258 while (base.IsRunning) 1379 while (base.IsRunningOutbound)
1259 { 1380 {
1260 m_scene.ThreadAlive(2); 1381 m_scene.ThreadAlive(2);
1261 try 1382 try
@@ -1523,7 +1644,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1523 if (!client.IsLoggingOut) 1644 if (!client.IsLoggingOut)
1524 { 1645 {
1525 client.IsLoggingOut = true; 1646 client.IsLoggingOut = true;
1526 client.Close(false); 1647 client.Close(false, false);
1527 } 1648 }
1528 } 1649 }
1529 } 1650 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index cfe7c9d..e7d8a30 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -30,6 +30,7 @@ using System.Net;
30using System.Net.Sockets; 30using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework;
33 34
34namespace OpenMetaverse 35namespace OpenMetaverse
35{ 36{
@@ -58,17 +59,29 @@ namespace OpenMetaverse
58 /// <summary>Flag to process packets asynchronously or synchronously</summary> 59 /// <summary>Flag to process packets asynchronously or synchronously</summary>
59 private bool m_asyncPacketHandling; 60 private bool m_asyncPacketHandling;
60 61
61 /// <summary>The all important shutdown flag</summary> 62 /// <summary>
62 private volatile bool m_shutdownFlag = true; 63 /// Pool to use for handling data. May be null if UsePools = false;
64 /// </summary>
65 protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
63 66
64 /// <summary>Returns true if the server is currently listening, otherwise false</summary> 67 /// <summary>
65 public bool IsRunning { get { return !m_shutdownFlag; } } 68 /// Are we to use object pool(s) to reduce memory churn when receiving data?
69 /// </summary>
70 public bool UsePools { get; protected set; }
71
72 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
73 public bool IsRunningInbound { get; private set; }
74
75 /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
76 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
77 public bool IsRunningOutbound { get; private set; }
66 78
67 /// <summary> 79 /// <summary>
68 /// Default constructor 80 /// Default constructor
69 /// </summary> 81 /// </summary>
70 /// <param name="bindAddress">Local IP address to bind the server to</param> 82 /// <param name="bindAddress">Local IP address to bind the server to</param>
71 /// <param name="port">Port to listening for incoming UDP packets on</param> 83 /// <param name="port">Port to listening for incoming UDP packets on</param>
84 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
72 public OpenSimUDPBase(IPAddress bindAddress, int port) 85 public OpenSimUDPBase(IPAddress bindAddress, int port)
73 { 86 {
74 m_localBindAddress = bindAddress; 87 m_localBindAddress = bindAddress;
@@ -76,7 +89,7 @@ namespace OpenMetaverse
76 } 89 }
77 90
78 /// <summary> 91 /// <summary>
79 /// Start the UDP server 92 /// Start inbound UDP packet handling.
80 /// </summary> 93 /// </summary>
81 /// <param name="recvBufferSize">The size of the receive buffer for 94 /// <param name="recvBufferSize">The size of the receive buffer for
82 /// the UDP socket. This value is passed up to the operating system 95 /// the UDP socket. This value is passed up to the operating system
@@ -91,11 +104,16 @@ namespace OpenMetaverse
91 /// manner (not throwing an exception when the remote side resets the 104 /// manner (not throwing an exception when the remote side resets the
92 /// connection). This call is ignored on Mono where the flag is not 105 /// connection). This call is ignored on Mono where the flag is not
93 /// necessary</remarks> 106 /// necessary</remarks>
94 public void Start(int recvBufferSize, bool asyncPacketHandling) 107 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
95 { 108 {
109 if (UsePools)
110 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
111 else
112 m_pool = null;
113
96 m_asyncPacketHandling = asyncPacketHandling; 114 m_asyncPacketHandling = asyncPacketHandling;
97 115
98 if (m_shutdownFlag) 116 if (!IsRunningInbound)
99 { 117 {
100 const int SIO_UDP_CONNRESET = -1744830452; 118 const int SIO_UDP_CONNRESET = -1744830452;
101 119
@@ -123,8 +141,7 @@ namespace OpenMetaverse
123 141
124 m_udpSocket.Bind(ipep); 142 m_udpSocket.Bind(ipep);
125 143
126 // we're not shutting down, we're starting up 144 IsRunningInbound = true;
127 m_shutdownFlag = false;
128 145
129 // kick off an async receive. The Start() method will return, the 146 // kick off an async receive. The Start() method will return, the
130 // actual receives will occur asynchronously and will be caught in 147 // actual receives will occur asynchronously and will be caught in
@@ -134,28 +151,41 @@ namespace OpenMetaverse
134 } 151 }
135 152
136 /// <summary> 153 /// <summary>
137 /// Stops the UDP server 154 /// Start outbound UDP packet handling.
138 /// </summary> 155 /// </summary>
139 public void Stop() 156 public void StartOutbound()
140 { 157 {
141 if (!m_shutdownFlag) 158 IsRunningOutbound = true;
159 }
160
161 public void StopInbound()
162 {
163 if (IsRunningInbound)
142 { 164 {
143 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 165 // wait indefinitely for a writer lock. Once this is called, the .NET runtime
144 // will deny any more reader locks, in effect blocking all other send/receive 166 // will deny any more reader locks, in effect blocking all other send/receive
145 // threads. Once we have the lock, we set shutdownFlag to inform the other 167 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
146 // threads that the socket is closed. 168 // threads that the socket is closed.
147 m_shutdownFlag = true; 169 IsRunningInbound = false;
148 m_udpSocket.Close(); 170 m_udpSocket.Close();
149 } 171 }
150 } 172 }
151 173
174 public void StopOutbound()
175 {
176 IsRunningOutbound = false;
177 }
178
152 private void AsyncBeginReceive() 179 private void AsyncBeginReceive()
153 { 180 {
154 // allocate a packet buffer 181 UDPPacketBuffer buf;
155 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 182
156 UDPPacketBuffer buf = new UDPPacketBuffer(); 183 if (UsePools)
184 buf = m_pool.GetObject();
185 else
186 buf = new UDPPacketBuffer();
157 187
158 if (!m_shutdownFlag) 188 if (IsRunningInbound)
159 { 189 {
160 try 190 try
161 { 191 {
@@ -208,7 +238,7 @@ namespace OpenMetaverse
208 { 238 {
209 // Asynchronous receive operations will complete here through the call 239 // Asynchronous receive operations will complete here through the call
210 // to AsyncBeginReceive 240 // to AsyncBeginReceive
211 if (!m_shutdownFlag) 241 if (IsRunningInbound)
212 { 242 {
213 // Asynchronous mode will start another receive before the 243 // Asynchronous mode will start another receive before the
214 // callback for this packet is even fired. Very parallel :-) 244 // callback for this packet is even fired. Very parallel :-)
@@ -217,8 +247,6 @@ namespace OpenMetaverse
217 247
218 // get the buffer that was created in AsyncBeginReceive 248 // get the buffer that was created in AsyncBeginReceive
219 // this is the received data 249 // this is the received data
220 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
221 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
222 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 250 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
223 251
224 try 252 try
@@ -235,7 +263,8 @@ namespace OpenMetaverse
235 catch (ObjectDisposedException) { } 263 catch (ObjectDisposedException) { }
236 finally 264 finally
237 { 265 {
238 //wrappedBuffer.Dispose(); 266 if (UsePools)
267 m_pool.ReturnObject(buffer);
239 268
240 // Synchronous mode waits until the packet callback completes 269 // Synchronous mode waits until the packet callback completes
241 // before starting the receive to fetch another packet 270 // before starting the receive to fetch another packet
@@ -248,7 +277,7 @@ namespace OpenMetaverse
248 277
249 public void AsyncBeginSend(UDPPacketBuffer buf) 278 public void AsyncBeginSend(UDPPacketBuffer buf)
250 { 279 {
251 if (!m_shutdownFlag) 280 if (IsRunningOutbound)
252 { 281 {
253 try 282 try
254 { 283 {
diff --git a/OpenSim/Framework/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 41d17c5..71f6fe1 100644
--- a/OpenSim/Framework/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -31,10 +31,10 @@ using System.Reflection;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.Packets; 32using OpenMetaverse.Packets;
33using log4net; 33using log4net;
34using OpenSim.Framework.Monitoring;
34 35
35namespace OpenSim.Framework 36namespace OpenSim.Region.ClientStack.LindenUDP
36{ 37{
37
38 public sealed class PacketPool 38 public sealed class PacketPool
39 { 39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -44,14 +44,28 @@ namespace OpenSim.Framework
44 private bool packetPoolEnabled = true; 44 private bool packetPoolEnabled = true;
45 private bool dataBlockPoolEnabled = true; 45 private bool dataBlockPoolEnabled = true;
46 46
47 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>(); 47 private PercentageStat m_packetsReusedStat = new PercentageStat(
48 "PacketsReused",
49 "Packets reused",
50 "clientstack",
51 "packetpool",
52 StatVerbosity.Debug,
53 "Number of packets reused out of all requests to the packet pool");
54
55 private PercentageStat m_blocksReusedStat = new PercentageStat(
56 "BlocksReused",
57 "Blocks reused",
58 "clientstack",
59 "packetpool",
60 StatVerbosity.Debug,
61 "Number of data blocks reused out of all requests to the packet pool");
48 62
49 private static Dictionary<Type, Stack<Object>> DataBlocks = 63 /// <summary>
50 new Dictionary<Type, Stack<Object>>(); 64 /// Pool of packets available for reuse.
65 /// </summary>
66 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
51 67
52 static PacketPool() 68 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
53 {
54 }
55 69
56 public static PacketPool Instance 70 public static PacketPool Instance
57 { 71 {
@@ -70,8 +84,21 @@ namespace OpenSim.Framework
70 get { return dataBlockPoolEnabled; } 84 get { return dataBlockPoolEnabled; }
71 } 85 }
72 86
87 private PacketPool()
88 {
89 StatsManager.RegisterStat(m_packetsReusedStat);
90 StatsManager.RegisterStat(m_blocksReusedStat);
91 }
92
93 /// <summary>
94 /// Gets a packet of the given type.
95 /// </summary>
96 /// <param name='type'></param>
97 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
73 public Packet GetPacket(PacketType type) 98 public Packet GetPacket(PacketType type)
74 { 99 {
100 m_packetsReusedStat.Consequent++;
101
75 Packet packet; 102 Packet packet;
76 103
77 if (!packetPoolEnabled) 104 if (!packetPoolEnabled)
@@ -87,6 +114,8 @@ namespace OpenSim.Framework
87 else 114 else
88 { 115 {
89 // Recycle old packages 116 // Recycle old packages
117 m_packetsReusedStat.Antecedent++;
118
90 packet = (pool[type]).Pop(); 119 packet = (pool[type]).Pop();
91 } 120 }
92 } 121 }
@@ -136,7 +165,7 @@ namespace OpenSim.Framework
136 { 165 {
137 PacketType type = GetType(bytes); 166 PacketType type = GetType(bytes);
138 167
139 Array.Clear(zeroBuffer, 0, zeroBuffer.Length); 168// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
140 169
141 int i = 0; 170 int i = 0;
142 Packet packet = GetPacket(type); 171 Packet packet = GetPacket(type);
@@ -183,6 +212,7 @@ namespace OpenSim.Framework
183 switch (packet.Type) 212 switch (packet.Type)
184 { 213 {
185 // List pooling packets here 214 // List pooling packets here
215 case PacketType.AgentUpdate:
186 case PacketType.PacketAck: 216 case PacketType.PacketAck:
187 case PacketType.ObjectUpdate: 217 case PacketType.ObjectUpdate:
188 case PacketType.ImprovedTerseObjectUpdate: 218 case PacketType.ImprovedTerseObjectUpdate:
@@ -209,16 +239,21 @@ namespace OpenSim.Framework
209 } 239 }
210 } 240 }
211 241
212 public static T GetDataBlock<T>() where T: new() 242 public T GetDataBlock<T>() where T: new()
213 { 243 {
214 lock (DataBlocks) 244 lock (DataBlocks)
215 { 245 {
246 m_blocksReusedStat.Consequent++;
247
216 Stack<Object> s; 248 Stack<Object> s;
217 249
218 if (DataBlocks.TryGetValue(typeof(T), out s)) 250 if (DataBlocks.TryGetValue(typeof(T), out s))
219 { 251 {
220 if (s.Count > 0) 252 if (s.Count > 0)
253 {
254 m_blocksReusedStat.Antecedent++;
221 return (T)s.Pop(); 255 return (T)s.Pop();
256 }
222 } 257 }
223 else 258 else
224 { 259 {
@@ -229,7 +264,7 @@ namespace OpenSim.Framework
229 } 264 }
230 } 265 }
231 266
232 public static void ReturnDataBlock<T>(T block) where T: new() 267 public void ReturnDataBlock<T>(T block) where T: new()
233 { 268 {
234 if (block == null) 269 if (block == null)
235 return; 270 return;
@@ -244,4 +279,4 @@ namespace OpenSim.Framework
244 } 279 }
245 } 280 }
246 } 281 }
247} 282} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 109a8e1..556df30 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
43 /// This will contain basic tests for the LindenUDP client stack 43 /// This will contain basic tests for the LindenUDP client stack
44 /// </summary> 44 /// </summary>
45 [TestFixture] 45 [TestFixture]
46 public class BasicCircuitTests 46 public class BasicCircuitTests : OpenSimTestCase
47 { 47 {
48 private Scene m_scene; 48 private Scene m_scene;
49 private TestLLUDPServer m_udpServer; 49 private TestLLUDPServer m_udpServer;
@@ -65,8 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
65 } 65 }
66 66
67 [SetUp] 67 [SetUp]
68 public void SetUp() 68 public override void SetUp()
69 { 69 {
70 base.SetUp();
70 m_scene = new SceneHelpers().SetupScene(); 71 m_scene = new SceneHelpers().SetupScene();
71 } 72 }
72 73
@@ -143,7 +144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
143 public void TestAddClient() 144 public void TestAddClient()
144 { 145 {
145 TestHelpers.InMethod(); 146 TestHelpers.InMethod();
146// XmlConfigurator.Configure(); 147// TestHelpers.EnableLogging();
147 148
148 AddUdpServer(); 149 AddUdpServer();
149 150
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
index 4672f8a..853b72d 100644
--- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs
+++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack
76 76
77 protected override void StartupSpecific() 77 protected override void StartupSpecific()
78 { 78 {
79 SceneManager = new SceneManager(); 79 SceneManager = SceneManager.Instance;
80 m_clientStackManager = CreateClientStackManager(); 80 m_clientStackManager = CreateClientStackManager();
81 81
82 Initialize(); 82 Initialize();
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
index 8a4fd8f..da1ff2e 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -57,39 +57,36 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
57 } 57 }
58 58
59 /// <summary> 59 /// <summary>
60 /// Return a xfer uploader if one does not already exist. 60 /// Return the xfer uploader for the given transaction.
61 /// </summary> 61 /// </summary>
62 /// <remarks>
63 /// If an uploader does not already exist for this transaction then it is created, otherwise the existing
64 /// uploader is returned.
65 /// </remarks>
62 /// <param name="transactionID"></param> 66 /// <param name="transactionID"></param>
63 /// <param name="assetID"> 67 /// <returns>The asset xfer uploader</returns>
64 /// We must transfer the new asset ID into the uploader on creation, otherwise 68 public AssetXferUploader RequestXferUploader(UUID transactionID)
65 /// we can see race conditions with other threads which can retrieve an item before it is updated with the new
66 /// asset id.
67 /// </param>
68 /// <returns>
69 /// The xfer uploader requested. Null if one is already in existence.
70 /// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple
71 /// transfers are made. Needs to be corrected.
72 /// </returns>
73 public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID)
74 { 69 {
70 AssetXferUploader uploader;
71
75 lock (XferUploaders) 72 lock (XferUploaders)
76 { 73 {
77 if (!XferUploaders.ContainsKey(transactionID)) 74 if (!XferUploaders.ContainsKey(transactionID))
78 { 75 {
79 AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile); 76 uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
80 77
81// m_log.DebugFormat( 78// m_log.DebugFormat(
82// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID); 79// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
83 80
84 XferUploaders.Add(transactionID, uploader); 81 XferUploaders.Add(transactionID, uploader);
85 82 }
86 return uploader; 83 else
84 {
85 uploader = XferUploaders[transactionID];
87 } 86 }
88 } 87 }
89 88
90 m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID); 89 return uploader;
91
92 return null;
93 } 90 }
94 91
95 public void HandleXfer(ulong xferID, uint packetID, byte[] data) 92 public void HandleXfer(ulong xferID, uint packetID, byte[] data)
@@ -151,117 +148,30 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
151 string description, string name, sbyte invType, 148 string description, string name, sbyte invType,
152 sbyte type, byte wearableType, uint nextOwnerMask) 149 sbyte type, byte wearableType, uint nextOwnerMask)
153 { 150 {
154 AssetXferUploader uploader = null; 151 AssetXferUploader uploader = RequestXferUploader(transactionID);
155
156 lock (XferUploaders)
157 {
158 if (XferUploaders.ContainsKey(transactionID))
159 uploader = XferUploaders[transactionID];
160 }
161 152
162 if (uploader != null) 153 uploader.RequestCreateInventoryItem(
163 { 154 remoteClient, folderID, callbackID,
164 uploader.RequestCreateInventoryItem( 155 description, name, invType, type, wearableType, nextOwnerMask);
165 remoteClient, transactionID, folderID,
166 callbackID, description, name, invType, type,
167 wearableType, nextOwnerMask);
168 156
169 return true; 157 return true;
170 }
171
172 return false;
173 }
174
175 /// <summary>
176 /// Get an uploaded asset. If the data is successfully retrieved,
177 /// the transaction will be removed.
178 /// </summary>
179 /// <param name="transactionID"></param>
180 /// <returns>The asset if the upload has completed, null if it has not.</returns>
181 private AssetBase GetTransactionAsset(UUID transactionID)
182 {
183 lock (XferUploaders)
184 {
185 if (XferUploaders.ContainsKey(transactionID))
186 {
187 AssetXferUploader uploader = XferUploaders[transactionID];
188 AssetBase asset = uploader.GetAssetData();
189 RemoveXferUploader(transactionID);
190
191 return asset;
192 }
193 }
194
195 return null;
196 } 158 }
197 159
198 public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, 160 public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
199 SceneObjectPart part, UUID transactionID, 161 SceneObjectPart part, UUID transactionID,
200 TaskInventoryItem item) 162 TaskInventoryItem item)
201 { 163 {
202 AssetXferUploader uploader = null; 164 AssetXferUploader uploader = RequestXferUploader(transactionID);
203
204 lock (XferUploaders)
205 {
206 if (XferUploaders.ContainsKey(transactionID))
207 uploader = XferUploaders[transactionID];
208 }
209
210 if (uploader != null)
211 {
212 AssetBase asset = GetTransactionAsset(transactionID);
213
214 // Only legacy viewers use this, and they prefer CAPS, which
215 // we have, so this really never runs.
216 // Allow it, but only for "safe" types.
217 if ((InventoryType)item.InvType != InventoryType.Notecard &&
218 (InventoryType)item.InvType != InventoryType.LSL)
219 return;
220 165
221 if (asset != null) 166 uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
222 {
223// m_log.DebugFormat(
224// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
225// item.Name, part.Name, transactionID);
226
227 asset.FullID = UUID.Random();
228 asset.Name = item.Name;
229 asset.Description = item.Description;
230 asset.Type = (sbyte)item.Type;
231 item.AssetID = asset.FullID;
232
233 m_Scene.AssetService.Store(asset);
234 }
235 }
236 else
237 {
238 m_log.ErrorFormat(
239 "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}",
240 transactionID, item.Name, part.Name);
241 }
242 } 167 }
243 168
244 public void RequestUpdateInventoryItem(IClientAPI remoteClient, 169 public void RequestUpdateInventoryItem(IClientAPI remoteClient,
245 UUID transactionID, InventoryItemBase item) 170 UUID transactionID, InventoryItemBase item)
246 { 171 {
247 AssetXferUploader uploader = null; 172 AssetXferUploader uploader = RequestXferUploader(transactionID);
248
249 lock (XferUploaders)
250 {
251 if (XferUploaders.ContainsKey(transactionID))
252 uploader = XferUploaders[transactionID];
253 }
254 173
255 if (uploader != null) 174 uploader.RequestUpdateInventoryItem(remoteClient, item);
256 {
257 uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item);
258 }
259 else
260 {
261 m_log.ErrorFormat(
262 "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}",
263 transactionID, item.Name, remoteClient.Name);
264 }
265 } 175 }
266 } 176 }
267} 177}
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
index 441c4ff..4bb8986 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
@@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
215 IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) 215 IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
216 { 216 {
217 m_log.DebugFormat( 217 m_log.DebugFormat(
218 "[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", 218 "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
219 item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); 219 item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
220 220
221 AgentAssetTransactions transactions = 221 AgentAssetTransactions transactions =
@@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
274 } 274 }
275 275
276 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); 276 AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
277 AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID); 277 AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
278 278 uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
279 if (uploader != null)
280 {
281 uploader.Initialise(remoteClient, assetID, transaction, type,
282 data, storeLocal, tempFile);
283 }
284 } 279 }
285 280
286 /// <summary> 281 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index 4cedfe6..f6dd5af 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
@@ -49,39 +49,75 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 /// <summary> 51 /// <summary>
52 /// Upload state.
53 /// </summary>
54 /// <remarks>
55 /// New -> Uploading -> Complete
56 /// </remarks>
57 private enum UploadState
58 {
59 New,
60 Uploading,
61 Complete
62 }
63
64 /// <summary>
52 /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we 65 /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
53 /// are performing a delayed update. 66 /// are performing a delayed update.
54 /// </summary> 67 /// </summary>
55 AgentAssetTransactions m_transactions; 68 AgentAssetTransactions m_transactions;
56 69
70 private UploadState m_uploadState = UploadState.New;
71
57 private AssetBase m_asset; 72 private AssetBase m_asset;
58 private UUID InventFolder = UUID.Zero; 73 private UUID InventFolder = UUID.Zero;
59 private sbyte invType = 0; 74 private sbyte invType = 0;
60 75
61 private bool m_createItem = false; 76 private bool m_createItem;
62 private uint m_createItemCallback = 0; 77 private uint m_createItemCallback;
63 private bool m_updateItem = false; 78
79 private bool m_updateItem;
64 private InventoryItemBase m_updateItemData; 80 private InventoryItemBase m_updateItemData;
65 81
82 private bool m_updateTaskItem;
83 private TaskInventoryItem m_updateTaskItemData;
84
66 private string m_description = String.Empty; 85 private string m_description = String.Empty;
67 private bool m_dumpAssetToFile; 86 private bool m_dumpAssetToFile;
68 private bool m_finished = false;
69 private string m_name = String.Empty; 87 private string m_name = String.Empty;
70 private bool m_storeLocal; 88// private bool m_storeLocal;
71 private uint nextPerm = 0; 89 private uint nextPerm = 0;
72 private IClientAPI ourClient; 90 private IClientAPI ourClient;
73 private UUID TransactionID = UUID.Zero; 91
92 private UUID m_transactionID;
93
74 private sbyte type = 0; 94 private sbyte type = 0;
75 private byte wearableType = 0; 95 private byte wearableType = 0;
76 private byte[] m_oldData = null; 96 private byte[] m_oldData = null;
77 public ulong XferID; 97 public ulong XferID;
78 private Scene m_Scene; 98 private Scene m_Scene;
79 99
80 public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) 100 /// <summary>
101 /// AssetXferUploader constructor
102 /// </summary>
103 /// <param name='transactions'>/param>
104 /// <param name='scene'></param>
105 /// <param name='transactionID'></param>
106 /// <param name='dumpAssetToFile'>
107 /// If true then when the asset is uploaded it is dumped to a file with the format
108 /// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat",
109 /// now.Year, now.Month, now.Day, now.Hour, now.Minute,
110 /// now.Second, m_asset.Name, m_asset.Type);
111 /// for debugging purposes.
112 /// </param>
113 public AssetXferUploader(
114 AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile)
81 { 115 {
116 m_asset = new AssetBase();
117
82 m_transactions = transactions; 118 m_transactions = transactions;
119 m_transactionID = transactionID;
83 m_Scene = scene; 120 m_Scene = scene;
84 m_asset = new AssetBase() { FullID = assetID };
85 m_dumpAssetToFile = dumpAssetToFile; 121 m_dumpAssetToFile = dumpAssetToFile;
86 } 122 }
87 123
@@ -127,30 +163,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
127 } 163 }
128 164
129 /// <summary> 165 /// <summary>
130 /// Initialise asset transfer from the client 166 /// Start asset transfer from the client
131 /// </summary> 167 /// </summary>
132 /// <param name="xferID"></param> 168 /// <param name="remoteClient"></param>
133 /// <param name="packetID"></param> 169 /// <param name="assetID"></param>
134 /// <param name="data"></param> 170 /// <param name="transaction"></param>
135 public void Initialise(IClientAPI remoteClient, UUID assetID, 171 /// <param name="type"></param>
136 UUID transaction, sbyte type, byte[] data, bool storeLocal, 172 /// <param name="data">
137 bool tempFile) 173 /// Optional data. If present then the asset is created immediately with this data
174 /// rather than requesting an upload from the client. The data must be longer than 2 bytes.
175 /// </param>
176 /// <param name="storeLocal"></param>
177 /// <param name="tempFile"></param>
178 public void StartUpload(
179 IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal,
180 bool tempFile)
138 { 181 {
139// m_log.DebugFormat( 182// m_log.DebugFormat(
140// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", 183// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}",
141// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); 184// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length);
142 185
186 lock (this)
187 {
188 if (m_uploadState != UploadState.New)
189 {
190 m_log.WarnFormat(
191 "[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.",
192 assetID, transaction, remoteClient.Name, m_uploadState);
193
194 return;
195 }
196
197 m_uploadState = UploadState.Uploading;
198 }
199
143 ourClient = remoteClient; 200 ourClient = remoteClient;
144 m_asset.Name = "blank"; 201
145 m_asset.Description = "empty"; 202 m_asset.FullID = assetID;
146 m_asset.Type = type; 203 m_asset.Type = type;
147 m_asset.CreatorID = remoteClient.AgentId.ToString(); 204 m_asset.CreatorID = remoteClient.AgentId.ToString();
148 m_asset.Data = data; 205 m_asset.Data = data;
149 m_asset.Local = storeLocal; 206 m_asset.Local = storeLocal;
150 m_asset.Temporary = tempFile; 207 m_asset.Temporary = tempFile;
151 208
152 TransactionID = transaction; 209// m_storeLocal = storeLocal;
153 m_storeLocal = storeLocal;
154 210
155 if (m_asset.Data.Length > 2) 211 if (m_asset.Data.Length > 2)
156 { 212 {
@@ -175,36 +231,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
175 231
176 protected void SendCompleteMessage() 232 protected void SendCompleteMessage()
177 { 233 {
178 ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true,
179 m_asset.FullID);
180
181 // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create 234 // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create
182 // message from other client UDP. 235 // message from other client UDP.
183 lock (this) 236 lock (this)
184 { 237 {
185 m_finished = true; 238 m_uploadState = UploadState.Complete;
239
240 ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
241
186 if (m_createItem) 242 if (m_createItem)
187 { 243 {
188 DoCreateItem(m_createItemCallback); 244 CompleteCreateItem(m_createItemCallback);
189 } 245 }
190 else if (m_updateItem) 246 else if (m_updateItem)
191 { 247 {
192 StoreAssetForItemUpdate(m_updateItemData); 248 CompleteItemUpdate(m_updateItemData);
193
194 // Remove ourselves from the list of transactions if completion was delayed until the transaction
195 // was complete.
196 // TODO: Should probably do the same for create item.
197 m_transactions.RemoveXferUploader(TransactionID);
198 } 249 }
199 else if (m_storeLocal) 250 else if (m_updateTaskItem)
200 { 251 {
201 m_Scene.AssetService.Store(m_asset); 252 CompleteTaskItemUpdate(m_updateTaskItemData);
202 } 253 }
254// else if (m_storeLocal)
255// {
256// m_Scene.AssetService.Store(m_asset);
257// }
203 } 258 }
204 259
205 m_log.DebugFormat( 260 m_log.DebugFormat(
206 "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", 261 "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
207 m_asset.FullID, TransactionID); 262 m_asset.FullID, m_transactionID);
208 263
209 if (m_dumpAssetToFile) 264 if (m_dumpAssetToFile)
210 { 265 {
@@ -232,40 +287,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
232 } 287 }
233 288
234 public void RequestCreateInventoryItem(IClientAPI remoteClient, 289 public void RequestCreateInventoryItem(IClientAPI remoteClient,
235 UUID transactionID, UUID folderID, uint callbackID, 290 UUID folderID, uint callbackID,
236 string description, string name, sbyte invType, 291 string description, string name, sbyte invType,
237 sbyte type, byte wearableType, uint nextOwnerMask) 292 sbyte type, byte wearableType, uint nextOwnerMask)
238 { 293 {
239 if (TransactionID == transactionID) 294 InventFolder = folderID;
295 m_name = name;
296 m_description = description;
297 this.type = type;
298 this.invType = invType;
299 this.wearableType = wearableType;
300 nextPerm = nextOwnerMask;
301 m_asset.Name = name;
302 m_asset.Description = description;
303 m_asset.Type = type;
304
305 // We must lock to avoid a race with a separate thread uploading the asset.
306 lock (this)
240 { 307 {
241 InventFolder = folderID; 308 if (m_uploadState == UploadState.Complete)
242 m_name = name;
243 m_description = description;
244 this.type = type;
245 this.invType = invType;
246 this.wearableType = wearableType;
247 nextPerm = nextOwnerMask;
248 m_asset.Name = name;
249 m_asset.Description = description;
250 m_asset.Type = type;
251
252 // We must lock to avoid a race with a separate thread uploading the asset.
253 lock (this)
254 { 309 {
255 if (m_finished) 310 CompleteCreateItem(callbackID);
256 { 311 }
257 DoCreateItem(callbackID); 312 else
258 } 313 {
259 else 314 m_createItem = true; //set flag so the inventory item is created when upload is complete
260 { 315 m_createItemCallback = callbackID;
261 m_createItem = true; //set flag so the inventory item is created when upload is complete
262 m_createItemCallback = callbackID;
263 }
264 } 316 }
265 } 317 }
266 } 318 }
267 319
268 public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) 320 public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
269 { 321 {
270 // We must lock to avoid a race with a separate thread uploading the asset. 322 // We must lock to avoid a race with a separate thread uploading the asset.
271 lock (this) 323 lock (this)
@@ -280,9 +332,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
280 item.AssetID = m_asset.FullID; 332 item.AssetID = m_asset.FullID;
281 m_Scene.InventoryService.UpdateItem(item); 333 m_Scene.InventoryService.UpdateItem(item);
282 334
283 if (m_finished) 335 if (m_uploadState == UploadState.Complete)
284 { 336 {
285 StoreAssetForItemUpdate(item); 337 CompleteItemUpdate(item);
286 } 338 }
287 else 339 else
288 { 340 {
@@ -296,20 +348,59 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
296 } 348 }
297 } 349 }
298 350
351 public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem)
352 {
353 // We must lock to avoid a race with a separate thread uploading the asset.
354 lock (this)
355 {
356 m_asset.Name = taskItem.Name;
357 m_asset.Description = taskItem.Description;
358 m_asset.Type = (sbyte)taskItem.Type;
359 taskItem.AssetID = m_asset.FullID;
360
361 if (m_uploadState == UploadState.Complete)
362 {
363 CompleteTaskItemUpdate(taskItem);
364 }
365 else
366 {
367 m_updateTaskItem = true;
368 m_updateTaskItemData = taskItem;
369 }
370 }
371 }
372
299 /// <summary> 373 /// <summary>
300 /// Store the asset for the given item. 374 /// Store the asset for the given item when it has been uploaded.
301 /// </summary> 375 /// </summary>
302 /// <param name="item"></param> 376 /// <param name="item"></param>
303 private void StoreAssetForItemUpdate(InventoryItemBase item) 377 private void CompleteItemUpdate(InventoryItemBase item)
304 { 378 {
305// m_log.DebugFormat( 379// m_log.DebugFormat(
306// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", 380// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
307// m_asset.FullID, item.Name, ourClient.Name); 381// m_asset.FullID, item.Name, ourClient.Name);
308 382
309 m_Scene.AssetService.Store(m_asset); 383 m_Scene.AssetService.Store(m_asset);
384
385 m_transactions.RemoveXferUploader(m_transactionID);
386 }
387
388 /// <summary>
389 /// Store the asset for the given task item when it has been uploaded.
390 /// </summary>
391 /// <param name="taskItem"></param>
392 private void CompleteTaskItemUpdate(TaskInventoryItem taskItem)
393 {
394// m_log.DebugFormat(
395// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}",
396// m_asset.FullID, taskItem.Name, ourClient.Name);
397
398 m_Scene.AssetService.Store(m_asset);
399
400 m_transactions.RemoveXferUploader(m_transactionID);
310 } 401 }
311 402
312 private void DoCreateItem(uint callbackID) 403 private void CompleteCreateItem(uint callbackID)
313 { 404 {
314 ValidateAssets(); 405 ValidateAssets();
315 m_Scene.AssetService.Store(m_asset); 406 m_Scene.AssetService.Store(m_asset);
@@ -339,6 +430,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
339 ourClient.SendInventoryItemCreateUpdate(item, callbackID); 430 ourClient.SendInventoryItemCreateUpdate(item, callbackID);
340 else 431 else
341 ourClient.SendAlertMessage("Unable to create inventory item"); 432 ourClient.SendAlertMessage("Unable to create inventory item");
433
434 m_transactions.RemoveXferUploader(m_transactionID);
342 } 435 }
343 436
344 private void ValidateAssets() 437 private void ValidateAssets()
@@ -416,7 +509,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
416 /// <returns>null if the asset has not finished uploading</returns> 509 /// <returns>null if the asset has not finished uploading</returns>
417 public AssetBase GetAssetData() 510 public AssetBase GetAssetData()
418 { 511 {
419 if (m_finished) 512 if (m_uploadState == UploadState.Complete)
420 { 513 {
421 ValidateAssets(); 514 ValidateAssets();
422 return m_asset; 515 return m_asset;
@@ -469,4 +562,3 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
469 } 562 }
470 } 563 }
471} 564}
472
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 7d7176f..d1a563c 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -52,7 +52,7 @@ using OpenSim.Services.Interfaces;
52[assembly: Addin("FlotsamAssetCache", "1.1")] 52[assembly: Addin("FlotsamAssetCache", "1.1")]
53[assembly: AddinDependency("OpenSim", "0.5")] 53[assembly: AddinDependency("OpenSim", "0.5")]
54 54
55namespace Flotsam.RegionModules.AssetCache 55namespace OpenSim.Region.CoreModules.Asset
56{ 56{
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] 57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
58 public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService 58 public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
@@ -107,8 +107,6 @@ namespace Flotsam.RegionModules.AssetCache
107 private IAssetService m_AssetService; 107 private IAssetService m_AssetService;
108 private List<Scene> m_Scenes = new List<Scene>(); 108 private List<Scene> m_Scenes = new List<Scene>();
109 109
110 private bool m_DeepScanBeforePurge;
111
112 public FlotsamAssetCache() 110 public FlotsamAssetCache()
113 { 111 {
114 m_InvalidChars.AddRange(Path.GetInvalidPathChars()); 112 m_InvalidChars.AddRange(Path.GetInvalidPathChars());
@@ -170,8 +168,6 @@ namespace Flotsam.RegionModules.AssetCache
170 m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen); 168 m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen);
171 169
172 m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt); 170 m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt);
173
174 m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", m_DeepScanBeforePurge);
175 } 171 }
176 172
177 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); 173 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
@@ -519,13 +515,10 @@ namespace Flotsam.RegionModules.AssetCache
519 // Purge all files last accessed prior to this point 515 // Purge all files last accessed prior to this point
520 DateTime purgeLine = DateTime.Now - m_FileExpiration; 516 DateTime purgeLine = DateTime.Now - m_FileExpiration;
521 517
522 // An optional deep scan at this point will ensure assets present in scenes, 518 // An asset cache may contain local non-temporary assets that are not in the asset service. Therefore,
523 // or referenced by objects in the scene, but not recently accessed 519 // before cleaning up expired files we must scan the objects in the scene to make sure that we retain
524 // are not purged. 520 // such local assets if they have not been recently accessed.
525 if (m_DeepScanBeforePurge) 521 TouchAllSceneAssets(false);
526 {
527 CacheScenes();
528 }
529 522
530 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 523 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
531 { 524 {
@@ -718,11 +711,14 @@ namespace Flotsam.RegionModules.AssetCache
718 711
719 /// <summary> 712 /// <summary>
720 /// Iterates through all Scenes, doing a deep scan through assets 713 /// Iterates through all Scenes, doing a deep scan through assets
721 /// to cache all assets present in the scene or referenced by assets 714 /// to update the access time of all assets present in the scene or referenced by assets
722 /// in the scene 715 /// in the scene.
723 /// </summary> 716 /// </summary>
724 /// <returns></returns> 717 /// <param name="storeUncached">
725 private int CacheScenes() 718 /// If true, then assets scanned which are not found in cache are added to the cache.
719 /// </param>
720 /// <returns>Number of distinct asset references found in the scene.</returns>
721 private int TouchAllSceneAssets(bool storeUncached)
726 { 722 {
727 UuidGatherer gatherer = new UuidGatherer(m_AssetService); 723 UuidGatherer gatherer = new UuidGatherer(m_AssetService);
728 724
@@ -745,7 +741,7 @@ namespace Flotsam.RegionModules.AssetCache
745 { 741 {
746 File.SetLastAccessTime(filename, DateTime.Now); 742 File.SetLastAccessTime(filename, DateTime.Now);
747 } 743 }
748 else 744 else if (storeUncached)
749 { 745 {
750 m_AssetService.Get(assetID.ToString()); 746 m_AssetService.Get(assetID.ToString());
751 } 747 }
@@ -873,13 +869,14 @@ namespace Flotsam.RegionModules.AssetCache
873 869
874 break; 870 break;
875 871
876
877 case "assets": 872 case "assets":
878 m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes."); 873 m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes.");
879 874
880 Util.FireAndForget(delegate { 875 Util.FireAndForget(delegate {
881 int assetsCached = CacheScenes(); 876 int assetReferenceTotal = TouchAllSceneAssets(true);
882 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); 877 m_log.InfoFormat(
878 "[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
879 assetReferenceTotal);
883 }); 880 });
884 881
885 break; 882 break;
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
index c91b25f..1c2bfd0 100644
--- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -35,7 +35,6 @@ using Nini.Config;
35using NUnit.Framework; 35using NUnit.Framework;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.Assets; 37using OpenMetaverse.Assets;
38using Flotsam.RegionModules.AssetCache;
39using OpenSim.Framework; 38using OpenSim.Framework;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 951afd7..e711afb 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -286,6 +286,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
286 286
287 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) 287 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
288 { 288 {
289 if (!Enabled)
290 return false;
291
292 if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp))
293 {
294 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
295 return true;
296 }
297
298 return false;
299 }
300
301 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
302 {
289 lock (sp.AttachmentsSyncLock) 303 lock (sp.AttachmentsSyncLock)
290 { 304 {
291// m_log.DebugFormat( 305// m_log.DebugFormat(
@@ -461,6 +475,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
461 475
462 public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) 476 public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId)
463 { 477 {
478 DetachSingleAttachmentToGround(sp, soLocalId, sp.AbsolutePosition, Quaternion.Identity);
479 }
480
481 public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot)
482 {
464 if (!Enabled) 483 if (!Enabled)
465 return; 484 return;
466 485
@@ -502,7 +521,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
502 so.FromItemID = UUID.Zero; 521 so.FromItemID = UUID.Zero;
503 522
504 SceneObjectPart rootPart = so.RootPart; 523 SceneObjectPart rootPart = so.RootPart;
505 so.AbsolutePosition = sp.AbsolutePosition; 524 so.AbsolutePosition = absolutePos;
525 if (absoluteRot != Quaternion.Identity)
526 {
527 so.UpdateGroupRotationR(absoluteRot);
528 }
506 so.AttachedAvatar = UUID.Zero; 529 so.AttachedAvatar = UUID.Zero;
507 rootPart.SetParentLocalId(0); 530 rootPart.SetParentLocalId(0);
508 so.ClearPartAttachmentData(); 531 so.ClearPartAttachmentData();
@@ -862,7 +885,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
862 // This will throw if the attachment fails 885 // This will throw if the attachment fails
863 try 886 try
864 { 887 {
865 AttachObject(sp, objatt, attachmentPt, false, false, false); 888 AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
866 } 889 }
867 catch (Exception e) 890 catch (Exception e)
868 { 891 {
@@ -933,6 +956,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
933 956
934 InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); 957 InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
935 item = m_scene.InventoryService.GetItem(item); 958 item = m_scene.InventoryService.GetItem(item);
959 if (item == null)
960 return;
961
936 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 962 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
937 if (changed && m_scene.AvatarFactory != null) 963 if (changed && m_scene.AvatarFactory != null)
938 { 964 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index d9a619d..4e9d3f9 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -62,7 +62,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
62 public class AttachmentsModuleTests : OpenSimTestCase 62 public class AttachmentsModuleTests : OpenSimTestCase
63 { 63 {
64 private AutoResetEvent m_chatEvent = new AutoResetEvent(false); 64 private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
65 private OSChatMessage m_osChatMessageReceived; 65// private OSChatMessage m_osChatMessageReceived;
66
67 // Used to test whether the operations have fired the attach event. Must be reset after each test.
68 private int m_numberOfAttachEventsFired;
66 69
67 [TestFixtureSetUp] 70 [TestFixtureSetUp]
68 public void FixtureInit() 71 public void FixtureInit()
@@ -83,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
83 { 86 {
84// Console.WriteLine("Got chat [{0}]", oscm.Message); 87// Console.WriteLine("Got chat [{0}]", oscm.Message);
85 88
86 m_osChatMessageReceived = oscm; 89// m_osChatMessageReceived = oscm;
87 m_chatEvent.Set(); 90 m_chatEvent.Set();
88 } 91 }
89 92
@@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
99 "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); 102 "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
100 SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); 103 SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
101 104
105 scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
106
102 return scene; 107 return scene;
103 } 108 }
104 109
@@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
181 TestHelpers.InMethod(); 186 TestHelpers.InMethod();
182// TestHelpers.EnableLogging(); 187// TestHelpers.EnableLogging();
183 188
189 m_numberOfAttachEventsFired = 0;
190
184 Scene scene = CreateTestScene(); 191 Scene scene = CreateTestScene();
185 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 192 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
186 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); 193 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@@ -189,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
189 196
190 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); 197 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
191 198
199 m_numberOfAttachEventsFired = 0;
192 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false); 200 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
193 201
194 // Check status on scene presence 202 // Check status on scene presence
@@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
216 224
217 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 225 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
218 226
219// TestHelpers.DisableLogging(); 227 // Check events
228 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
220 } 229 }
221 230
222 /// <summary> 231 /// <summary>
@@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
228 TestHelpers.InMethod(); 237 TestHelpers.InMethod();
229// TestHelpers.EnableLogging(); 238// TestHelpers.EnableLogging();
230 239
240 m_numberOfAttachEventsFired = 0;
241
231 Scene scene = CreateTestScene(); 242 Scene scene = CreateTestScene();
232 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 243 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
233 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); 244 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@@ -247,6 +258,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
247 258
248 Assert.That(sp.HasAttachments(), Is.False); 259 Assert.That(sp.HasAttachments(), Is.False);
249 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 260 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
261
262 // Check events
263 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
250 } 264 }
251 265
252 [Test] 266 [Test]
@@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
261 275
262 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); 276 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
263 277
278 m_numberOfAttachEventsFired = 0;
264 scene.AttachmentsModule.RezSingleAttachmentFromInventory( 279 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
265 sp, attItem.ID, (uint)AttachmentPoint.Chest); 280 sp, attItem.ID, (uint)AttachmentPoint.Chest);
266 281
@@ -280,6 +295,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
280 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 295 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
281 296
282 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 297 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
298
299 // Check events
300 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
283 } 301 }
284 302
285 /// <summary> 303 /// <summary>
@@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
338 ISceneEntity so 356 ISceneEntity so
339 = scene.AttachmentsModule.RezSingleAttachmentFromInventory( 357 = scene.AttachmentsModule.RezSingleAttachmentFromInventory(
340 sp, attItem.ID, (uint)AttachmentPoint.Chest); 358 sp, attItem.ID, (uint)AttachmentPoint.Chest);
359
360 m_numberOfAttachEventsFired = 0;
341 scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId); 361 scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
342 362
343 // Check scene presence status 363 // Check scene presence status
@@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
353 373
354 // Check object in scene 374 // Check object in scene
355 Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); 375 Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
376
377 // Check events
378 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
356 } 379 }
357 380
358 [Test] 381 [Test]
@@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
369 SceneObjectGroup so 392 SceneObjectGroup so
370 = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory( 393 = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
371 sp, attItem.ID, (uint)AttachmentPoint.Chest); 394 sp, attItem.ID, (uint)AttachmentPoint.Chest);
395
396 m_numberOfAttachEventsFired = 0;
372 scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so); 397 scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
373 398
374 // Check status on scene presence 399 // Check status on scene presence
@@ -380,6 +405,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
380 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); 405 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
381 406
382 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); 407 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
408
409 // Check events
410 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
383 } 411 }
384 412
385 /// <summary> 413 /// <summary>
@@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
461 489
462 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; 490 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
463 491
464 scene.IncomingCloseAgent(presence.UUID); 492 m_numberOfAttachEventsFired = 0;
493 scene.IncomingCloseAgent(presence.UUID, false);
465 494
466 // Check that we can't retrieve this attachment from the scene. 495 // Check that we can't retrieve this attachment from the scene.
467 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); 496 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
497
498 // Check events
499 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
468 } 500 }
469 501
470 [Test] 502 [Test]
@@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
480 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); 512 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
481 acd.Appearance = new AvatarAppearance(); 513 acd.Appearance = new AvatarAppearance();
482 acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); 514 acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
515
516 m_numberOfAttachEventsFired = 0;
483 ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); 517 ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
484 518
485 Assert.That(presence.HasAttachments(), Is.True); 519 Assert.That(presence.HasAttachments(), Is.True);
@@ -502,6 +536,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
502 Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 536 Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
503 537
504 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 538 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
539
540 // Check events. We expect OnAttach to fire on login.
541 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
505 } 542 }
506 543
507 [Test] 544 [Test]
@@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
522 559
523 Vector3 newPosition = new Vector3(1, 2, 4); 560 Vector3 newPosition = new Vector3(1, 2, 4);
524 561
562 m_numberOfAttachEventsFired = 0;
525 scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient); 563 scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
526 564
527 Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition)); 565 Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
528 Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition)); 566 Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
567
568 // Check events
569 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
529 } 570 }
530 571
531 [Test] 572 [Test]
@@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
574 Vector3 teleportPosition = new Vector3(10, 11, 12); 615 Vector3 teleportPosition = new Vector3(10, 11, 12);
575 Vector3 teleportLookAt = new Vector3(20, 21, 22); 616 Vector3 teleportLookAt = new Vector3(20, 21, 22);
576 617
618 m_numberOfAttachEventsFired = 0;
577 sceneA.RequestTeleportLocation( 619 sceneA.RequestTeleportLocation(
578 beforeTeleportSp.ControllingClient, 620 beforeTeleportSp.ControllingClient,
579 sceneB.RegionInfo.RegionHandle, 621 sceneB.RegionInfo.RegionHandle,
@@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
616 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); 658 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
617 659
618 Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); 660 Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
619 }
620 661
621 // I'm commenting this test because scene setup NEEDS InventoryService to 662 // Check events
622 // be non-null 663 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
623 //[Test] 664 }
624// public void T032_CrossAttachments()
625// {
626// TestHelpers.InMethod();
627//
628// ScenePresence presence = scene.GetScenePresence(agent1);
629// ScenePresence presence2 = scene2.GetScenePresence(agent1);
630// presence2.AddAttachment(sog1);
631// presence2.AddAttachment(sog2);
632//
633// ISharedRegionModule serialiser = new SerialiserModule();
634// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
635// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
636//
637// Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
638//
639// //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
640// Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
641// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
642// }
643 } 665 }
644} 666}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index bd7bd82..e3bf997 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -525,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
525 { 525 {
526 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) 526 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
527 { 527 {
528 for (int j = 0; j < appearance.Wearables[j].Count; j++) 528 for (int j = 0; j < appearance.Wearables[i].Count; j++)
529 { 529 {
530 if (appearance.Wearables[i][j].ItemID == UUID.Zero) 530 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
531 continue; 531 continue;
@@ -533,6 +533,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
533 // Ignore ruth's assets 533 // Ignore ruth's assets
534 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) 534 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
535 continue; 535 continue;
536
536 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); 537 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
537 baseItem = invService.GetItem(baseItem); 538 baseItem = invService.GetItem(baseItem);
538 539
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
index d942e87..5ec0ea9 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
141 client.FirstName+" "+client.LastName, 141 client.FirstName+" "+client.LastName,
142 destID, (byte)211, false, 142 destID, (byte)211, false,
143 String.Empty, 143 String.Empty,
144 transactionID, false, new Vector3(), new byte[0]), 144 transactionID, false, new Vector3(), new byte[0], true),
145 delegate(bool success) {} ); 145 delegate(bool success) {} );
146 } 146 }
147 } 147 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 24ec435..11db18a 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -482,9 +482,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
482 Util.FireAndForget( 482 Util.FireAndForget(
483 delegate 483 delegate
484 { 484 {
485 m_log.DebugFormat( 485// m_log.DebugFormat(
486 "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}", 486// "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
487 friendList.Count, agentID, online); 487// friendList.Count, agentID, online);
488 488
489 // Notify about this user status 489 // Notify about this user status
490 StatusNotify(friendList, agentID, online); 490 StatusNotify(friendList, agentID, online);
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 716cc69..82816d9 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
206 transferModule.SendInstantMessage(new GridInstantMessage( 206 transferModule.SendInstantMessage(new GridInstantMessage(
207 m_scene, godID, "God", agentID, (byte)250, false, 207 m_scene, godID, "God", agentID, (byte)250, false,
208 Utils.BytesToString(reason), UUID.Zero, true, 208 Utils.BytesToString(reason), UUID.Zero, true,
209 new Vector3(), new byte[] {(byte)kickflags}), 209 new Vector3(), new byte[] {(byte)kickflags}, true),
210 delegate(bool success) {} ); 210 delegate(bool success) {} );
211 } 211 }
212 return; 212 return;
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
index b112b6d..12a05b3 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
@@ -350,38 +350,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
350 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); 350 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
351 } 351 }
352 352
353 /// <summary> 353// /// <summary>
354 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where 354// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
355 /// an account exists with the same name as the creator, though not the same id. 355// /// an account exists with the same name as the creator, though not the same id.
356 /// </summary> 356// /// </summary>
357 [Test] 357// [Test]
358 public void TestLoadIarV0_1SameNameCreator() 358// public void TestLoadIarV0_1SameNameCreator()
359 { 359// {
360 TestHelpers.InMethod(); 360// TestHelpers.InMethod();
361// log4net.Config.XmlConfigurator.Configure(); 361// TestHelpers.EnableLogging();
362 362//
363 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); 363// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
364 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); 364// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
365 365//
366 m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); 366// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
367 InventoryItemBase foundItem1 367// InventoryItemBase foundItem1
368 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); 368// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
369 369//
370 Assert.That( 370// Assert.That(
371 foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), 371// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
372 "Loaded item non-uuid creator doesn't match original"); 372// "Loaded item non-uuid creator doesn't match original");
373 Assert.That( 373// Assert.That(
374 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), 374// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
375 "Loaded item uuid creator doesn't match original"); 375// "Loaded item uuid creator doesn't match original");
376 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), 376// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
377 "Loaded item owner doesn't match inventory reciever"); 377// "Loaded item owner doesn't match inventory reciever");
378 378//
379 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); 379// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
380 string xmlData = Utils.BytesToString(asset1.Data); 380// string xmlData = Utils.BytesToString(asset1.Data);
381 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 381// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
382 382//
383 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); 383// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
384 } 384// }
385 385
386 /// <summary> 386 /// <summary>
387 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where 387 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index c14cb17..21dff4b 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -313,6 +313,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
313 m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); 313 m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
314 } 314 }
315 } 315 }
316
317 // XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name>
318 // to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis
319 // of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously
320 // done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here.
316 else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) 321 else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
317 { 322 {
318 UUID destinationFolderID = UUID.Zero; 323 UUID destinationFolderID = UUID.Zero;
@@ -324,6 +329,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
324 329
325 if (destinationFolderID != UUID.Zero) 330 if (destinationFolderID != UUID.Zero)
326 { 331 {
332 InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId);
333 if (destinationFolder == null)
334 {
335 m_log.WarnFormat(
336 "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist",
337 client.Name, scene.Name, destinationFolderID);
338
339 return;
340 }
341
327 IInventoryService invService = scene.InventoryService; 342 IInventoryService invService = scene.InventoryService;
328 343
329 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip 344 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
@@ -331,9 +346,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
331 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); 346 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
332 item = invService.GetItem(item); 347 item = invService.GetItem(item);
333 InventoryFolderBase folder = null; 348 InventoryFolderBase folder = null;
349 UUID? previousParentFolderID = null;
334 350
335 if (item != null) // It's an item 351 if (item != null) // It's an item
336 { 352 {
353 previousParentFolderID = item.Folder;
337 item.Folder = destinationFolderID; 354 item.Folder = destinationFolderID;
338 355
339 invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); 356 invService.DeleteItems(item.Owner, new List<UUID>() { item.ID });
@@ -346,10 +363,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
346 363
347 if (folder != null) // It's a folder 364 if (folder != null) // It's a folder
348 { 365 {
366 previousParentFolderID = folder.ParentID;
349 folder.ParentID = destinationFolderID; 367 folder.ParentID = destinationFolderID;
350 invService.MoveFolder(folder); 368 invService.MoveFolder(folder);
351 } 369 }
352 } 370 }
371
372 // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
373 if (previousParentFolderID != null)
374 {
375 InventoryFolderBase previousParentFolder
376 = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
377 previousParentFolder = invService.GetFolder(previousParentFolder);
378 scene.SendInventoryUpdate(client, previousParentFolder, true, true);
379
380 scene.SendInventoryUpdate(client, destinationFolder, true, true);
381 }
353 } 382 }
354 } 383 }
355 else if ( 384 else if (
@@ -370,9 +399,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
370 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); 399 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
371 item = invService.GetItem(item); 400 item = invService.GetItem(item);
372 InventoryFolderBase folder = null; 401 InventoryFolderBase folder = null;
402 UUID? previousParentFolderID = null;
373 403
374 if (item != null && trashFolder != null) 404 if (item != null && trashFolder != null)
375 { 405 {
406 previousParentFolderID = item.Folder;
376 item.Folder = trashFolder.ID; 407 item.Folder = trashFolder.ID;
377 408
378 // Diva comment: can't we just update this item??? 409 // Diva comment: can't we just update this item???
@@ -388,6 +419,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
388 419
389 if (folder != null & trashFolder != null) 420 if (folder != null & trashFolder != null)
390 { 421 {
422 previousParentFolderID = folder.ParentID;
391 folder.ParentID = trashFolder.ID; 423 folder.ParentID = trashFolder.ID;
392 invService.MoveFolder(folder); 424 invService.MoveFolder(folder);
393 client.SendBulkUpdateInventory(folder); 425 client.SendBulkUpdateInventory(folder);
@@ -408,6 +440,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
408 client.SendAgentAlertMessage("Unable to delete "+ 440 client.SendAgentAlertMessage("Unable to delete "+
409 "received inventory" + reason, false); 441 "received inventory" + reason, false);
410 } 442 }
443 // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
444 else if (previousParentFolderID != null)
445 {
446 InventoryFolderBase previousParentFolder
447 = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
448 previousParentFolder = invService.GetFolder(previousParentFolder);
449 scene.SendInventoryUpdate(client, previousParentFolder, true, true);
450
451 scene.SendInventoryUpdate(client, trashFolder, true, true);
452 }
411 453
412 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID)); 454 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
413 455
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
index 92cf9d1..9c369f6 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
@@ -186,7 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
186 client.FirstName+" "+client.LastName, targetid, 186 client.FirstName+" "+client.LastName, targetid,
187 (byte)InstantMessageDialog.RequestTeleport, false, 187 (byte)InstantMessageDialog.RequestTeleport, false,
188 message, sessionID, false, presence.AbsolutePosition, 188 message, sessionID, false, presence.AbsolutePosition,
189 new Byte[0]); 189 new Byte[0], true);
190 m.RegionID = client.Scene.RegionInfo.RegionID.Guid; 190 m.RegionID = client.Scene.RegionInfo.RegionID.Guid;
191 191
192 m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); 192 m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message);
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index a889984..1949459 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
173 client.FirstName+" "+client.LastName, targetid, 173 client.FirstName+" "+client.LastName, targetid,
174 (byte)InstantMessageDialog.GodLikeRequestTeleport, false, 174 (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
175 message, dest, false, presence.AbsolutePosition, 175 message, dest, false, presence.AbsolutePosition,
176 new Byte[0]); 176 new Byte[0], true);
177 } 177 }
178 else 178 else
179 { 179 {
@@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
181 client.FirstName+" "+client.LastName, targetid, 181 client.FirstName+" "+client.LastName, targetid,
182 (byte)InstantMessageDialog.RequestTeleport, false, 182 (byte)InstantMessageDialog.RequestTeleport, false,
183 message, dest, false, presence.AbsolutePosition, 183 message, dest, false, presence.AbsolutePosition,
184 new Byte[0]); 184 new Byte[0], true);
185 } 185 }
186 186
187 if (m_TransferModule != null) 187 if (m_TransferModule != null)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 880b2cc..ffc362f 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -327,6 +327,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
327 return; 327 return;
328 } 328 }
329 329
330 // Validate assorted conditions
331 string reason = string.Empty;
332 if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
333 {
334 sp.ControllingClient.SendTeleportFailed(reason);
335 return;
336 }
337
330 // 338 //
331 // This is it 339 // This is it
332 // 340 //
@@ -358,6 +366,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
358 } 366 }
359 } 367 }
360 368
369 // Nothing to validate here
370 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
371 {
372 reason = String.Empty;
373 return true;
374 }
375
361 /// <summary> 376 /// <summary>
362 /// Determines whether this instance is within the max transfer distance. 377 /// Determines whether this instance is within the max transfer distance.
363 /// </summary> 378 /// </summary>
@@ -473,10 +488,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
473 // both regions 488 // both regions
474 if (sp.ParentID != (uint)0) 489 if (sp.ParentID != (uint)0)
475 sp.StandUp(); 490 sp.StandUp();
476
477 else if (sp.Flying) 491 else if (sp.Flying)
478 teleportFlags |= (uint)TeleportFlags.IsFlying; 492 teleportFlags |= (uint)TeleportFlags.IsFlying;
479 493
494 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
495 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
480 sp.ControllingClient.SendTeleportStart(teleportFlags); 496 sp.ControllingClient.SendTeleportStart(teleportFlags);
481 497
482 // the avatar.Close below will clear the child region list. We need this below for (possibly) 498 // the avatar.Close below will clear the child region list. We need this below for (possibly)
@@ -552,8 +568,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
552 // So let's wait 568 // So let's wait
553 Thread.Sleep(200); 569 Thread.Sleep(200);
554 570
571 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
572 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
573 // only on TeleportFinish). This is untested for region teleport between different simulators
574 // though this probably also works.
555 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 575 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
556
557 } 576 }
558 else 577 else
559 { 578 {
@@ -574,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
574 593
575 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); 594 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
576 595
577 if (!UpdateAgent(reg, finalDestination, agent)) 596 if (!UpdateAgent(reg, finalDestination, agent, sp))
578 { 597 {
579 // Region doesn't take it 598 // Region doesn't take it
580 m_log.WarnFormat( 599 m_log.WarnFormat(
@@ -650,7 +669,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
650 // an agent cannot teleport back to this region if it has teleported away. 669 // an agent cannot teleport back to this region if it has teleported away.
651 Thread.Sleep(3000); 670 Thread.Sleep(3000);
652 671
653 sp.Scene.IncomingCloseAgent(sp.UUID); 672 sp.Scene.IncomingCloseAgent(sp.UUID, false);
654 } 673 }
655 else 674 else
656 { 675 {
@@ -701,7 +720,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
701 return success; 720 return success;
702 } 721 }
703 722
704 protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) 723 protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp)
705 { 724 {
706 return Scene.SimulationService.UpdateAgent(finalDestination, agent); 725 return Scene.SimulationService.UpdateAgent(finalDestination, agent);
707 } 726 }
@@ -1013,6 +1032,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1013 Scene initiatingScene) 1032 Scene initiatingScene)
1014 { 1033 {
1015 Thread.Sleep(10000); 1034 Thread.Sleep(10000);
1035
1016 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1036 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1017 if (im != null) 1037 if (im != null)
1018 { 1038 {
@@ -1025,11 +1045,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1025 (uint)(int)position.X, 1045 (uint)(int)position.X,
1026 (uint)(int)position.Y, 1046 (uint)(int)position.Y,
1027 (uint)(int)position.Z); 1047 (uint)(int)position.Z);
1028 GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero, 1048
1029 "Region", agent.UUID, 1049 GridInstantMessage m
1030 (byte)InstantMessageDialog.GodLikeRequestTeleport, false, 1050 = new GridInstantMessage(
1031 "", gotoLocation, false, new Vector3(127, 0, 0), 1051 initiatingScene,
1032 new Byte[0]); 1052 UUID.Zero,
1053 "Region",
1054 agent.UUID,
1055 (byte)InstantMessageDialog.GodLikeRequestTeleport,
1056 false,
1057 "",
1058 gotoLocation,
1059 false,
1060 new Vector3(127, 0, 0),
1061 new Byte[0],
1062 false);
1063
1033 im.SendInstantMessage(m, delegate(bool success) 1064 im.SendInstantMessage(m, delegate(bool success)
1034 { 1065 {
1035 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success); 1066 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 3010b59..0aee0d4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -54,6 +54,59 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
54 54
55 private GatekeeperServiceConnector m_GatekeeperConnector; 55 private GatekeeperServiceConnector m_GatekeeperConnector;
56 56
57 protected bool m_RestrictAppearanceAbroad;
58 protected string m_AccountName;
59 protected List<AvatarAppearance> m_ExportedAppearances;
60 protected List<AvatarAttachment> m_Attachs;
61
62 protected List<AvatarAppearance> ExportedAppearance
63 {
64 get
65 {
66 if (m_ExportedAppearances != null)
67 return m_ExportedAppearances;
68
69 m_ExportedAppearances = new List<AvatarAppearance>();
70 m_Attachs = new List<AvatarAttachment>();
71
72 string[] names = m_AccountName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
73
74 foreach (string name in names)
75 {
76 string[] parts = name.Trim().Split();
77 if (parts.Length != 2)
78 {
79 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Wrong user account name format {0}. Specify 'First Last'", name);
80 return null;
81 }
82 UserAccount account = Scene.UserAccountService.GetUserAccount(UUID.Zero, parts[0], parts[1]);
83 if (account == null)
84 {
85 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unknown account {0}", m_AccountName);
86 return null;
87 }
88 AvatarAppearance a = Scene.AvatarService.GetAppearance(account.PrincipalID);
89 if (a != null)
90 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Successfully retrieved appearance for {0}", name);
91
92 foreach (AvatarAttachment att in a.GetAttachments())
93 {
94 InventoryItemBase item = new InventoryItemBase(att.ItemID, account.PrincipalID);
95 item = Scene.InventoryService.GetItem(item);
96 if (item != null)
97 a.SetAttachment(att.AttachPoint, att.ItemID, item.AssetID);
98 else
99 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to retrieve item {0} from inventory {1}", att.ItemID, name);
100 }
101
102 m_ExportedAppearances.Add(a);
103 m_Attachs.AddRange(a.GetAttachments());
104 }
105
106 return m_ExportedAppearances;
107 }
108 }
109
57 #region ISharedRegionModule 110 #region ISharedRegionModule
58 111
59 public override string Name 112 public override string Name
@@ -72,8 +125,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
72 { 125 {
73 IConfig transferConfig = source.Configs["EntityTransfer"]; 126 IConfig transferConfig = source.Configs["EntityTransfer"];
74 if (transferConfig != null) 127 if (transferConfig != null)
128 {
75 m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0); 129 m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0);
76 130
131 m_RestrictAppearanceAbroad = transferConfig.GetBoolean("RestrictAppearanceAbroad", false);
132 if (m_RestrictAppearanceAbroad)
133 {
134 m_AccountName = transferConfig.GetString("AccountForAppearance", string.Empty);
135 if (m_AccountName == string.Empty)
136 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is on, but no account has been given for avatar appearance!");
137 }
138 }
139
77 InitialiseCommon(source); 140 InitialiseCommon(source);
78 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); 141 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
79 } 142 }
@@ -85,7 +148,36 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
85 base.AddRegion(scene); 148 base.AddRegion(scene);
86 149
87 if (m_Enabled) 150 if (m_Enabled)
151 {
88 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); 152 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
153 scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
154 }
155 }
156
157 void OnIncomingSceneObject(SceneObjectGroup so)
158 {
159 if (!so.IsAttachment)
160 return;
161
162 if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar))
163 return;
164
165 // foreign user
166 AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar);
167 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
168 {
169 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
170 {
171 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
172 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url);
173 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
174 HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
175 uuidGatherer.GatherAssetUuids(so, ids);
176
177 foreach (KeyValuePair<UUID, AssetType> kvp in ids)
178 uuidGatherer.FetchAsset(kvp.Key);
179 }
180 }
89 } 181 }
90 182
91 protected override void OnNewClient(IClientAPI client) 183 protected override void OnNewClient(IClientAPI client)
@@ -120,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
120 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 212 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
121 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); 213 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
122 214
123 if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 215 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
124 { 216 {
125 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); 217 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
126 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 218 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@@ -140,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
140 return true; 232 return true;
141 233
142 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); 234 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
143 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 235 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
144 return true; 236 return true;
145 237
146 return false; 238 return false;
@@ -153,6 +245,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
153 { 245 {
154 // Log them out of this grid 246 // Log them out of this grid
155 Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); 247 Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
248 string userId = Scene.UserManagementModule.GetUserUUI(sp.UUID);
249 Scene.GridUserService.LoggedOut(userId, UUID.Zero, Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
156 } 250 }
157 } 251 }
158 252
@@ -162,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
162 reason = string.Empty; 256 reason = string.Empty;
163 logout = false; 257 logout = false;
164 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); 258 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
165 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 259 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
166 { 260 {
167 // this user is going to another grid 261 // this user is going to another grid
168 // check if HyperGrid teleport is allowed, based on user level 262 // check if HyperGrid teleport is allowed, based on user level
@@ -200,6 +294,124 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
200 TeleportHome(id, client); 294 TeleportHome(id, client);
201 } 295 }
202 296
297 protected override bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
298 {
299 reason = "Please wear your grid's allowed appearance before teleporting to another grid";
300 if (!m_RestrictAppearanceAbroad)
301 return true;
302
303 // The rest is only needed for controlling appearance
304
305 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
306 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
307 {
308 // this user is going to another grid
309 if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))
310 {
311 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Checking generic appearance");
312
313 // Check wearables
314 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
315 {
316 for (int j = 0; j < sp.Appearance.Wearables[i].Count; j++)
317 {
318 if (sp.Appearance.Wearables[i] == null)
319 continue;
320
321 bool found = false;
322 foreach (AvatarAppearance a in ExportedAppearance)
323 if (a.Wearables[i] != null)
324 {
325 found = true;
326 break;
327 }
328
329 if (!found)
330 {
331 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
332 return false;
333 }
334
335 found = false;
336 foreach (AvatarAppearance a in ExportedAppearance)
337 if (sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID)
338 {
339 found = true;
340 break;
341 }
342
343 if (!found)
344 {
345 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
346 return false;
347 }
348 }
349 }
350
351 // Check attachments
352 foreach (AvatarAttachment att in sp.Appearance.GetAttachments())
353 {
354 bool found = false;
355 foreach (AvatarAttachment att2 in m_Attachs)
356 {
357 if (att2.AssetID == att.AssetID)
358 {
359 found = true;
360 break;
361 }
362 }
363 if (!found)
364 {
365 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Attachment not allowed to go outside {0}", att.AttachPoint);
366 return false;
367 }
368 }
369 }
370 }
371
372 reason = string.Empty;
373 return true;
374 }
375
376
377 //protected override bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agentData, ScenePresence sp)
378 //{
379 // int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
380 // if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
381 // {
382 // // this user is going to another grid
383 // if (m_RestrictAppearanceAbroad && Scene.UserManagementModule.IsLocalGridUser(agentData.AgentID))
384 // {
385 // // We need to strip the agent off its appearance
386 // m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Sending generic appearance");
387
388 // // Delete existing npc attachments
389 // Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, false);
390
391 // // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet since it doesn't transfer attachments
392 // AvatarAppearance newAppearance = new AvatarAppearance(ExportedAppearance, true);
393 // sp.Appearance = newAppearance;
394
395 // // Rez needed npc attachments
396 // Scene.AttachmentsModule.RezAttachments(sp);
397
398
399 // IAvatarFactoryModule module = Scene.RequestModuleInterface<IAvatarFactoryModule>();
400 // //module.SendAppearance(sp.UUID);
401 // module.RequestRebake(sp, false);
402
403 // Scene.AttachmentsModule.CopyAttachments(sp, agentData);
404 // agentData.Appearance = sp.Appearance;
405 // }
406 // }
407
408 // foreach (AvatarAttachment a in agentData.Appearance.GetAttachments())
409 // m_log.DebugFormat("[XXX]: {0}-{1}", a.ItemID, a.AssetID);
410
411
412 // return base.UpdateAgent(reg, finalDestination, agentData, sp);
413 //}
414
203 public override bool TeleportHome(UUID id, IClientAPI client) 415 public override bool TeleportHome(UUID id, IClientAPI client)
204 { 416 {
205 m_log.DebugFormat( 417 m_log.DebugFormat(
@@ -375,4 +587,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
375 return region; 587 return region;
376 } 588 }
377 } 589 }
378} \ No newline at end of file 590}
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index eaadc1b..f8ec6de 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -71,19 +71,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
71 71
72 #region Internal functions 72 #region Internal functions
73 73
74 public AssetBase FetchAsset(string url, UUID assetID) 74 public AssetMetadata FetchMetadata(string url, UUID assetID)
75 { 75 {
76 if (!url.EndsWith("/") && !url.EndsWith("=")) 76 if (!url.EndsWith("/") && !url.EndsWith("="))
77 url = url + "/"; 77 url = url + "/";
78 78
79 AssetBase asset = m_scene.AssetService.Get(url + assetID.ToString()); 79 AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
80 80
81 if (asset != null) 81 if (meta != null)
82 { 82 m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
83 m_log.DebugFormat("[HG ASSET MAPPER]: Copied asset {0} from {1} to local asset server. ", asset.ID, url); 83 else
84 return asset; 84 m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
85 } 85
86 return null; 86 return meta;
87 } 87 }
88 88
89 public bool PostAsset(string url, AssetBase asset) 89 public bool PostAsset(string url, AssetBase asset)
@@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
93 if (!url.EndsWith("/") && !url.EndsWith("=")) 93 if (!url.EndsWith("/") && !url.EndsWith("="))
94 url = url + "/"; 94 url = url + "/";
95 95
96 bool success = true;
96 // See long comment in AssetCache.AddAsset 97 // See long comment in AssetCache.AddAsset
97 if (!asset.Temporary || asset.Local) 98 if (!asset.Temporary || asset.Local)
98 { 99 {
@@ -103,14 +104,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
103 // not having a global naming infrastructure 104 // not having a global naming infrastructure
104 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID); 105 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
105 Copy(asset, asset1); 106 Copy(asset, asset1);
106 try 107 asset1.ID = url + asset.ID;
107 {
108 asset1.ID = url + asset.ID;
109 }
110 catch
111 {
112 m_log.Warn("[HG ASSET MAPPER]: Oops.");
113 }
114 108
115 AdjustIdentifiers(asset1.Metadata); 109 AdjustIdentifiers(asset1.Metadata);
116 if (asset1.Metadata.Type == (sbyte)AssetType.Object) 110 if (asset1.Metadata.Type == (sbyte)AssetType.Object)
@@ -118,11 +112,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
118 else 112 else
119 asset1.Data = asset.Data; 113 asset1.Data = asset.Data;
120 114
121 m_scene.AssetService.Store(asset1); 115 string id = m_scene.AssetService.Store(asset1);
122 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url); 116 if (id == string.Empty)
117 {
118 m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
119 success = false;
120 }
121 else
122 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
123 } 123 }
124 return true; 124 return success;
125 } 125 }
126 else 126 else
127 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache."); 127 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
128 128
@@ -222,28 +222,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
222 222
223 public void Get(UUID assetID, UUID ownerID, string userAssetURL) 223 public void Get(UUID assetID, UUID ownerID, string userAssetURL)
224 { 224 {
225 // Get the item from the remote asset server onto the local AssetCache 225 // Get the item from the remote asset server onto the local AssetService
226 // and place an entry in m_assetMap
227
228 m_log.Debug("[HG ASSET MAPPER]: Fetching object " + assetID + " from asset server " + userAssetURL);
229 AssetBase asset = FetchAsset(userAssetURL, assetID);
230 226
231 if (asset != null) 227 AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
232 { 228 if (meta == null)
233 // OK, now fetch the inside. 229 return;
234 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
235 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
236 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
237 if (ids.ContainsKey(assetID))
238 ids.Remove(assetID);
239 foreach (UUID uuid in ids.Keys)
240 FetchAsset(userAssetURL, uuid);
241 230
242 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL); 231 // The act of gathering UUIDs downloads the assets from the remote server
232 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
233 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
234 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
243 235
244 }
245 else
246 m_log.Warn("[HG ASSET MAPPER]: Could not fetch asset from remote asset server " + userAssetURL);
247 } 236 }
248 237
249 238
@@ -257,19 +246,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
257 if (asset != null) 246 if (asset != null)
258 { 247 {
259 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 248 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
260 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); 249 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
261 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); 250 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
251 bool success = false;
262 foreach (UUID uuid in ids.Keys) 252 foreach (UUID uuid in ids.Keys)
263 { 253 {
264 asset = m_scene.AssetService.Get(uuid.ToString()); 254 asset = m_scene.AssetService.Get(uuid.ToString());
265 if (asset == null) 255 if (asset == null)
266 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid); 256 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
267 else 257 else
268 PostAsset(userAssetURL, asset); 258 success = PostAsset(userAssetURL, asset);
269 } 259 }
270 260
271 // maybe all pieces got there... 261 // maybe all pieces got there...
272 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); 262 if (!success)
263 m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
264 else
265 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
273 266
274 } 267 }
275 else 268 else
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index cf72b58..80257bd 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -263,8 +263,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
263 //} 263 //}
264 264
265 // OK, we're done fetching. Pass it up to the default RezObject 265 // OK, we're done fetching. Pass it up to the default RezObject
266 return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, 266 SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
267 RezSelected, RemoveItem, fromTaskID, attachment); 267 RezSelected, RemoveItem, fromTaskID, attachment);
268
269 if (sog == null)
270 remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
271
272 return sog;
268 273
269 } 274 }
270 275
@@ -308,6 +313,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
308 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID) 313 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
309 { 314 {
310 InventoryItemBase item = base.GetItem(agentID, itemID); 315 InventoryItemBase item = base.GetItem(agentID, itemID);
316 if (item == null)
317 return null;
311 318
312 string userAssetServer = string.Empty; 319 string userAssetServer = string.Empty;
313 if (IsForeignUser(agentID, out userAssetServer)) 320 if (IsForeignUser(agentID, out userAssetServer))
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
index e135c21..e411585 100644
--- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
@@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
95 { 95 {
96 foreach (IMonitor monitor in m_staticMonitors) 96 foreach (IMonitor monitor in m_staticMonitors)
97 { 97 {
98 m_log.InfoFormat( 98 MainConsole.Instance.OutputFormat(
99 "[MONITOR MODULE]: {0} reports {1} = {2}", 99 "[MONITOR MODULE]: {0} reports {1} = {2}",
100 m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue()); 100 m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
101 } 101 }
102 102
103 foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats()) 103 foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
104 { 104 {
105 m_log.InfoFormat( 105 MainConsole.Instance.OutputFormat(
106 "[MONITOR MODULE]: {0} reports {1} = {2}", 106 "[MONITOR MODULE]: {0} reports {1} = {2}",
107 m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value); 107 m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
108 } 108 }
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
index 65e4c90..fd8d5e3 100755
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -1,161 +1,170 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.IO; 29using System.IO;
30using System.Text; 30using System.Text;
31using log4net; 31using log4net;
32 32
33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging 33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Class for writing a high performance, high volume log file. 36 /// Class for writing a high performance, high volume log file.
37 /// Sometimes, to debug, one has a high volume logging to do and the regular 37 /// Sometimes, to debug, one has a high volume logging to do and the regular
38 /// log file output is not appropriate. 38 /// log file output is not appropriate.
39 /// Create a new instance with the parameters needed and 39 /// Create a new instance with the parameters needed and
40 /// call Write() to output a line. Call Close() when finished. 40 /// call Write() to output a line. Call Close() when finished.
41 /// If created with no parameters, it will not log anything. 41 /// If created with no parameters, it will not log anything.
42 /// </summary> 42 /// </summary>
43 public class LogWriter : IDisposable 43 public class LogWriter : IDisposable
44 { 44 {
45 public bool Enabled { get; private set; } 45 public bool Enabled { get; private set; }
46 46
47 private string m_logDirectory = "."; 47 private string m_logDirectory = ".";
48 private int m_logMaxFileTimeMin = 5; // 5 minutes 48 private int m_logMaxFileTimeMin = 5; // 5 minutes
49 public String LogFileHeader { get; set; } 49 public String LogFileHeader { get; set; }
50 50
51 private StreamWriter m_logFile = null; 51 private StreamWriter m_logFile = null;
52 private TimeSpan m_logFileLife; 52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime; 53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object(); 54 private Object m_logFileWriteLock = new Object();
55 55
56 // set externally when debugging. If let 'null', this does not write any error messages. 56 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null; 57 public ILog ErrorLogger = null;
58 private string LogHeader = "[LOG WRITER]"; 58 private string LogHeader = "[LOG WRITER]";
59 59
60 /// <summary> 60 /// <summary>
61 /// Create a log writer that will not write anything. Good for when not enabled 61 /// Create a log writer that will not write anything. Good for when not enabled
62 /// but the write statements are still in the code. 62 /// but the write statements are still in the code.
63 /// </summary> 63 /// </summary>
64 public LogWriter() 64 public LogWriter()
65 { 65 {
66 Enabled = false; 66 Enabled = false;
67 m_logFile = null; 67 m_logFile = null;
68 } 68 }
69 69
70 /// <summary> 70 /// <summary>
71 /// Create a log writer instance. 71 /// Create a log writer instance.
72 /// </summary> 72 /// </summary>
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> 73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> 74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> 75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime) 76 public LogWriter(string dir, string headr, int maxFileTime)
77 { 77 {
78 m_logDirectory = dir == null ? "." : dir; 78 m_logDirectory = dir == null ? "." : dir;
79 79
80 LogFileHeader = headr == null ? "log-" : headr; 80 LogFileHeader = headr == null ? "log-" : headr;
81 81
82 m_logMaxFileTimeMin = maxFileTime; 82 m_logMaxFileTimeMin = maxFileTime;
83 if (m_logMaxFileTimeMin < 1) 83 if (m_logMaxFileTimeMin < 1)
84 m_logMaxFileTimeMin = 5; 84 m_logMaxFileTimeMin = 5;
85 85
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); 86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife; 87 m_logFileEndTime = DateTime.Now + m_logFileLife;
88 88
89 Enabled = true; 89 Enabled = true;
90 } 90 }
91 91
92 public void Dispose() 92 public void Dispose()
93 { 93 {
94 this.Close(); 94 this.Close();
95 } 95 }
96 96
97 public void Close() 97 public void Close()
98 { 98 {
99 Enabled = false; 99 Enabled = false;
100 if (m_logFile != null) 100 if (m_logFile != null)
101 { 101 {
102 m_logFile.Close(); 102 m_logFile.Close();
103 m_logFile.Dispose(); 103 m_logFile.Dispose();
104 m_logFile = null; 104 m_logFile = null;
105 } 105 }
106 } 106 }
107 107
108 public void Write(string line, params object[] args) 108 public void Write(string line, params object[] args)
109 { 109 {
110 if (!Enabled) return; 110 if (!Enabled) return;
111 Write(String.Format(line, args)); 111 Write(String.Format(line, args));
112 } 112 }
113 113
114 public void Write(string line) 114 public void Flush()
115 { 115 {
116 if (!Enabled) return; 116 if (!Enabled) return;
117 try 117 if (m_logFile != null)
118 { 118 {
119 lock (m_logFileWriteLock) 119 m_logFile.Flush();
120 { 120 }
121 DateTime now = DateTime.Now; 121 }
122 if (m_logFile == null || now > m_logFileEndTime) 122
123 { 123 public void Write(string line)
124 if (m_logFile != null) 124 {
125 { 125 if (!Enabled) return;
126 m_logFile.Close(); 126 try
127 m_logFile.Dispose(); 127 {
128 m_logFile = null; 128 lock (m_logFileWriteLock)
129 } 129 {
130 130 DateTime now = DateTime.Now;
131 // First log file or time has expired, start writing to a new log file 131 if (m_logFile == null || now > m_logFileEndTime)
132 m_logFileEndTime = now + m_logFileLife; 132 {
133 string path = (m_logDirectory.Length > 0 ? m_logDirectory 133 if (m_logFile != null)
134 + System.IO.Path.DirectorySeparatorChar.ToString() : "") 134 {
135 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); 135 m_logFile.Close();
136 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write)); 136 m_logFile.Dispose();
137 } 137 m_logFile = null;
138 if (m_logFile != null) 138 }
139 { 139
140 StringBuilder buff = new StringBuilder(line.Length + 25); 140 // First log file or time has expired, start writing to a new log file
141 buff.Append(now.ToString("yyyyMMddHHmmssfff")); 141 m_logFileEndTime = now + m_logFileLife;
142 // buff.Append(now.ToString("yyyyMMddHHmmss")); 142 string path = (m_logDirectory.Length > 0 ? m_logDirectory
143 buff.Append(","); 143 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
144 buff.Append(line); 144 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
145 buff.Append("\r\n"); 145 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
146 m_logFile.Write(buff.ToString()); 146 }
147 } 147 if (m_logFile != null)
148 } 148 {
149 } 149 StringBuilder buff = new StringBuilder(line.Length + 25);
150 catch (Exception e) 150 buff.Append(now.ToString("yyyyMMddHHmmssfff"));
151 { 151 // buff.Append(now.ToString("yyyyMMddHHmmss"));
152 if (ErrorLogger != null) 152 buff.Append(",");
153 { 153 buff.Append(line);
154 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e); 154 buff.Append("\r\n");
155 } 155 m_logFile.Write(buff.ToString());
156 Enabled = false; 156 }
157 } 157 }
158 return; 158 }
159 } 159 catch (Exception e)
160 } 160 {
161} \ No newline at end of file 161 if (ErrorLogger != null)
162 {
163 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
164 }
165 Enabled = false;
166 }
167 return;
168 }
169 }
170}
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
index 4eecaa2..acefc97 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
@@ -137,6 +137,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
137 ud.FirstName = words[0]; 137 ud.FirstName = words[0];
138 ud.LastName = "@" + words[1]; 138 ud.LastName = "@" + words[1];
139 users.Add(ud); 139 users.Add(ud);
140 // WARNING! that uriStr is not quite right... it may be missing the / at the end,
141 // which will cause trouble (duplicate entries on some tables). We should
142 // get the UUI instead from the UAS. TO BE FIXED.
140 AddUser(userID, names[0], names[1], uriStr); 143 AddUser(userID, names[0], names[1], uriStr);
141 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]); 144 m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]);
142 } 145 }
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index f4ed67b..b4811da 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Console; 33using OpenSim.Framework.Console;
34using OpenSim.Region.ClientStack.LindenUDP;
34using OpenSim.Region.Framework; 35using OpenSim.Region.Framework;
35using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
@@ -429,8 +430,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
429 430
430 public void AddUser(UUID uuid, string first, string last, string homeURL) 431 public void AddUser(UUID uuid, string first, string last, string homeURL)
431 { 432 {
432 // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); 433 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
433
434 AddUser(uuid, homeURL + ";" + first + " " + last); 434 AddUser(uuid, homeURL + ";" + first + " " + last);
435 } 435 }
436 436
@@ -553,8 +553,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
553 MainConsole.Instance.Output("-----------------------------------------------------------------------------"); 553 MainConsole.Instance.Output("-----------------------------------------------------------------------------");
554 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) 554 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
555 { 555 {
556 MainConsole.Instance.Output(String.Format("{0} {1} {2}", 556 MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
557 kvp.Key, kvp.Value.FirstName, kvp.Value.LastName)); 557 kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
558 } 558 }
559 559
560 return; 560 return;
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs
new file mode 100644
index 0000000..fce9490
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTexture.cs
@@ -0,0 +1,61 @@
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.Drawing;
30using OpenSim.Region.Framework.Interfaces;
31
32namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
33{
34 public class DynamicTexture : IDynamicTexture
35 {
36 public string InputCommands { get; private set; }
37 public Uri InputUri { get; private set; }
38 public string InputParams { get; private set; }
39 public byte[] Data { get; private set; }
40 public Size Size { get; private set; }
41 public bool IsReuseable { get; private set; }
42
43 public DynamicTexture(string inputCommands, string inputParams, byte[] data, Size size, bool isReuseable)
44 {
45 InputCommands = inputCommands;
46 InputParams = inputParams;
47 Data = data;
48 Size = size;
49 IsReuseable = isReuseable;
50 }
51
52 public DynamicTexture(Uri inputUri, string inputParams, byte[] data, Size size, bool isReuseable)
53 {
54 InputUri = inputUri;
55 InputParams = inputParams;
56 Data = data;
57 Size = size;
58 IsReuseable = isReuseable;
59 }
60 }
61} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
index 18bd018..1f340df 100644
--- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -42,13 +42,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
42{ 42{
43 public class DynamicTextureModule : IRegionModule, IDynamicTextureManager 43 public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
44 { 44 {
45 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 private const int ALL_SIDES = -1; 47 private const int ALL_SIDES = -1;
48 48
49 public const int DISP_EXPIRE = 1; 49 public const int DISP_EXPIRE = 1;
50 public const int DISP_TEMP = 2; 50 public const int DISP_TEMP = 2;
51 51
52 /// <summary>
53 /// If true then where possible dynamic textures are reused.
54 /// </summary>
55 public bool ReuseTextures { get; set; }
56
57 /// <summary>
58 /// If false, then textures which have a low data size are not reused when ReuseTextures = true.
59 /// </summary>
60 /// <remarks>
61 /// LL viewers 3.3.4 and before appear to not fully render textures pulled from the viewer cache if those
62 /// textures have a relatively high pixel surface but a small data size. Typically, this appears to happen
63 /// if the data size is smaller than the viewer's discard level 2 size estimate. So if this is setting is
64 /// false, textures smaller than the calculation in IsSizeReuseable are always regenerated rather than reused
65 /// to work around this problem.</remarks>
66 public bool ReuseLowDataTextures { get; set; }
67
52 private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>(); 68 private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>();
53 69
54 private Dictionary<string, IDynamicTextureRender> RenderPlugins = 70 private Dictionary<string, IDynamicTextureRender> RenderPlugins =
@@ -56,6 +72,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
56 72
57 private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>(); 73 private Dictionary<UUID, DynamicTextureUpdater> Updaters = new Dictionary<UUID, DynamicTextureUpdater>();
58 74
75 /// <summary>
76 /// Record dynamic textures that we can reuse for a given data and parameter combination rather than
77 /// regenerate.
78 /// </summary>
79 /// <remarks>
80 /// Key is string.Format("{0}{1}", data
81 /// </remarks>
82 private Cache m_reuseableDynamicTextures;
83
59 #region IDynamicTextureManager Members 84 #region IDynamicTextureManager Members
60 85
61 public void RegisterRender(string handleType, IDynamicTextureRender render) 86 public void RegisterRender(string handleType, IDynamicTextureRender render)
@@ -69,17 +94,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
69 /// <summary> 94 /// <summary>
70 /// Called by code which actually renders the dynamic texture to supply texture data. 95 /// Called by code which actually renders the dynamic texture to supply texture data.
71 /// </summary> 96 /// </summary>
72 /// <param name="id"></param> 97 /// <param name="updaterId"></param>
73 /// <param name="data"></param> 98 /// <param name="texture"></param>
74 public void ReturnData(UUID id, byte[] data) 99 public void ReturnData(UUID updaterId, IDynamicTexture texture)
75 { 100 {
76 DynamicTextureUpdater updater = null; 101 DynamicTextureUpdater updater = null;
77 102
78 lock (Updaters) 103 lock (Updaters)
79 { 104 {
80 if (Updaters.ContainsKey(id)) 105 if (Updaters.ContainsKey(updaterId))
81 { 106 {
82 updater = Updaters[id]; 107 updater = Updaters[updaterId];
83 } 108 }
84 } 109 }
85 110
@@ -88,7 +113,16 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
88 if (RegisteredScenes.ContainsKey(updater.SimUUID)) 113 if (RegisteredScenes.ContainsKey(updater.SimUUID))
89 { 114 {
90 Scene scene = RegisteredScenes[updater.SimUUID]; 115 Scene scene = RegisteredScenes[updater.SimUUID];
91 updater.DataReceived(data, scene); 116 UUID newTextureID = updater.DataReceived(texture.Data, scene);
117
118 if (ReuseTextures
119 && !updater.BlendWithOldTexture
120 && texture.IsReuseable
121 && (ReuseLowDataTextures || IsDataSizeReuseable(texture)))
122 {
123 m_reuseableDynamicTextures.Store(
124 GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID);
125 }
92 } 126 }
93 } 127 }
94 128
@@ -104,6 +138,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
104 } 138 }
105 } 139 }
106 140
141 /// <summary>
142 /// Determines whether the texture is reuseable based on its data size.
143 /// </summary>
144 /// <remarks>
145 /// This is a workaround for a viewer bug where very small data size textures relative to their pixel size
146 /// are not redisplayed properly when pulled from cache. The calculation here is based on the typical discard
147 /// level of 2, a 'rate' of 0.125 and 4 components (which makes for a factor of 0.5).
148 /// </remarks>
149 /// <returns></returns>
150 private bool IsDataSizeReuseable(IDynamicTexture texture)
151 {
152// Console.WriteLine("{0} {1}", texture.Size.Width, texture.Size.Height);
153 int discardLevel2DataThreshold = (int)Math.Ceiling((texture.Size.Width >> 2) * (texture.Size.Height >> 2) * 0.5);
154
155// m_log.DebugFormat(
156// "[DYNAMIC TEXTURE MODULE]: Discard level 2 threshold {0}, texture data length {1}",
157// discardLevel2DataThreshold, texture.Data.Length);
158
159 return discardLevel2DataThreshold < texture.Data.Length;
160 }
161
107 public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, 162 public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
108 string extraParams, int updateTimer) 163 string extraParams, int updateTimer)
109 { 164 {
@@ -167,22 +222,61 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
167 public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, 222 public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data,
168 string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face) 223 string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face)
169 { 224 {
170 if (RenderPlugins.ContainsKey(contentType)) 225 if (!RenderPlugins.ContainsKey(contentType))
226 return UUID.Zero;
227
228 Scene scene;
229 RegisteredScenes.TryGetValue(simID, out scene);
230
231 if (scene == null)
232 return UUID.Zero;
233
234 SceneObjectPart part = scene.GetSceneObjectPart(primID);
235
236 if (part == null)
237 return UUID.Zero;
238
239 // If we want to reuse dynamic textures then we have to ignore any request from the caller to expire
240 // them.
241 if (ReuseTextures)
242 disp = disp & ~DISP_EXPIRE;
243
244 DynamicTextureUpdater updater = new DynamicTextureUpdater();
245 updater.SimUUID = simID;
246 updater.PrimID = primID;
247 updater.ContentType = contentType;
248 updater.BodyData = data;
249 updater.UpdateTimer = updateTimer;
250 updater.UpdaterID = UUID.Random();
251 updater.Params = extraParams;
252 updater.BlendWithOldTexture = SetBlending;
253 updater.FrontAlpha = AlphaValue;
254 updater.Face = face;
255 updater.Url = "Local image";
256 updater.Disp = disp;
257
258 object objReusableTextureUUID = null;
259
260 if (ReuseTextures && !updater.BlendWithOldTexture)
171 { 261 {
172 DynamicTextureUpdater updater = new DynamicTextureUpdater(); 262 string reuseableTextureKey = GenerateReusableTextureKey(data, extraParams);
173 updater.SimUUID = simID; 263 objReusableTextureUUID = m_reuseableDynamicTextures.Get(reuseableTextureKey);
174 updater.PrimID = primID; 264
175 updater.ContentType = contentType; 265 if (objReusableTextureUUID != null)
176 updater.BodyData = data; 266 {
177 updater.UpdateTimer = updateTimer; 267 // If something else has removed this temporary asset from the cache, detect and invalidate
178 updater.UpdaterID = UUID.Random(); 268 // our cached uuid.
179 updater.Params = extraParams; 269 if (scene.AssetService.GetMetadata(objReusableTextureUUID.ToString()) == null)
180 updater.BlendWithOldTexture = SetBlending; 270 {
181 updater.FrontAlpha = AlphaValue; 271 m_reuseableDynamicTextures.Invalidate(reuseableTextureKey);
182 updater.Face = face; 272 objReusableTextureUUID = null;
183 updater.Url = "Local image"; 273 }
184 updater.Disp = disp; 274 }
275 }
185 276
277 // We cannot reuse a dynamic texture if the data is going to be blended with something already there.
278 if (objReusableTextureUUID == null)
279 {
186 lock (Updaters) 280 lock (Updaters)
187 { 281 {
188 if (!Updaters.ContainsKey(updater.UpdaterID)) 282 if (!Updaters.ContainsKey(updater.UpdaterID))
@@ -191,11 +285,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
191 } 285 }
192 } 286 }
193 287
288// m_log.DebugFormat(
289// "[DYNAMIC TEXTURE MODULE]: Requesting generation of new dynamic texture for {0} in {1}",
290// part.Name, part.ParentGroup.Scene.Name);
291
194 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); 292 RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
195 return updater.UpdaterID;
196 } 293 }
197 294 else
198 return UUID.Zero; 295 {
296// m_log.DebugFormat(
297// "[DYNAMIC TEXTURE MODULE]: Reusing cached texture {0} for {1} in {2}",
298// objReusableTextureUUID, part.Name, part.ParentGroup.Scene.Name);
299
300 // No need to add to updaters as the texture is always the same. Not that this functionality
301 // apppears to be implemented anyway.
302 updater.UpdatePart(part, (UUID)objReusableTextureUUID);
303 }
304
305 return updater.UpdaterID;
306 }
307
308 private string GenerateReusableTextureKey(string data, string extraParams)
309 {
310 return string.Format("{0}{1}", data, extraParams);
199 } 311 }
200 312
201 public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, 313 public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize,
@@ -215,6 +327,13 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
215 327
216 public void Initialise(Scene scene, IConfigSource config) 328 public void Initialise(Scene scene, IConfigSource config)
217 { 329 {
330 IConfig texturesConfig = config.Configs["Textures"];
331 if (texturesConfig != null)
332 {
333 ReuseTextures = texturesConfig.GetBoolean("ReuseDynamicTextures", false);
334 ReuseLowDataTextures = texturesConfig.GetBoolean("ReuseDynamicLowDataTextures", false);
335 }
336
218 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) 337 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
219 { 338 {
220 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); 339 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
@@ -224,6 +343,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
224 343
225 public void PostInitialise() 344 public void PostInitialise()
226 { 345 {
346 if (ReuseTextures)
347 {
348 m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative);
349 m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0);
350 }
227 } 351 }
228 352
229 public void Close() 353 public void Close()
@@ -269,9 +393,60 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
269 } 393 }
270 394
271 /// <summary> 395 /// <summary>
396 /// Update the given part with the new texture.
397 /// </summary>
398 /// <returns>
399 /// The old texture UUID.
400 /// </returns>
401 public UUID UpdatePart(SceneObjectPart part, UUID textureID)
402 {
403 UUID oldID;
404
405 lock (part)
406 {
407 // mostly keep the values from before
408 Primitive.TextureEntry tmptex = part.Shape.Textures;
409
410 // FIXME: Need to return the appropriate ID if only a single face is replaced.
411 oldID = tmptex.DefaultTexture.TextureID;
412
413 if (Face == ALL_SIDES)
414 {
415 oldID = tmptex.DefaultTexture.TextureID;
416 tmptex.DefaultTexture.TextureID = textureID;
417 }
418 else
419 {
420 try
421 {
422 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
423 texface.TextureID = textureID;
424 tmptex.FaceTextures[Face] = texface;
425 }
426 catch (Exception)
427 {
428 tmptex.DefaultTexture.TextureID = textureID;
429 }
430 }
431
432 // I'm pretty sure we always want to force this to true
433 // I'm pretty sure noone whats to set fullbright true if it wasn't true before.
434 // tmptex.DefaultTexture.Fullbright = true;
435
436 part.UpdateTextureEntry(tmptex.GetBytes());
437 }
438
439 return oldID;
440 }
441
442 /// <summary>
272 /// Called once new texture data has been received for this updater. 443 /// Called once new texture data has been received for this updater.
273 /// </summary> 444 /// </summary>
274 public void DataReceived(byte[] data, Scene scene) 445 /// <param name="data"></param>
446 /// <param name="scene"></param>
447 /// <param name="isReuseable">True if the data given is reuseable.</param>
448 /// <returns>The asset UUID given to the incoming data.</returns>
449 public UUID DataReceived(byte[] data, Scene scene)
275 { 450 {
276 SceneObjectPart part = scene.GetSceneObjectPart(PrimID); 451 SceneObjectPart part = scene.GetSceneObjectPart(PrimID);
277 452
@@ -281,7 +456,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
281 String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); 456 String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url);
282 scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, 457 scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say,
283 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); 458 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false);
284 return; 459
460 return UUID.Zero;
285 } 461 }
286 462
287 byte[] assetData = null; 463 byte[] assetData = null;
@@ -319,56 +495,29 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
319 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); 495 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
320 if (cacheLayerDecode != null) 496 if (cacheLayerDecode != null)
321 { 497 {
322 cacheLayerDecode.Decode(asset.FullID, asset.Data); 498 if (!cacheLayerDecode.Decode(asset.FullID, asset.Data))
323 cacheLayerDecode = null; 499 m_log.WarnFormat(
500 "[DYNAMIC TEXTURE MODULE]: Decoding of dynamically generated asset {0} for {1} in {2} failed",
501 asset.ID, part.Name, part.ParentGroup.Scene.Name);
324 } 502 }
325 503
326 UUID oldID = UUID.Zero; 504 UUID oldID = UpdatePart(part, asset.FullID);
327
328 lock (part)
329 {
330 // mostly keep the values from before
331 Primitive.TextureEntry tmptex = part.Shape.Textures;
332
333 // remove the old asset from the cache
334 oldID = tmptex.DefaultTexture.TextureID;
335
336 if (Face == ALL_SIDES)
337 {
338 tmptex.DefaultTexture.TextureID = asset.FullID;
339 }
340 else
341 {
342 try
343 {
344 Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face);
345 texface.TextureID = asset.FullID;
346 tmptex.FaceTextures[Face] = texface;
347 }
348 catch (Exception)
349 {
350 tmptex.DefaultTexture.TextureID = asset.FullID;
351 }
352 }
353
354 // I'm pretty sure we always want to force this to true
355 // I'm pretty sure noone whats to set fullbright true if it wasn't true before.
356 // tmptex.DefaultTexture.Fullbright = true;
357
358 part.UpdateTextureEntry(tmptex.GetBytes());
359 }
360 505
361 if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) 506 if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0))
362 { 507 {
363 if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); 508 if (oldAsset == null)
509 oldAsset = scene.AssetService.Get(oldID.ToString());
510
364 if (oldAsset != null) 511 if (oldAsset != null)
365 { 512 {
366 if (oldAsset.Temporary == true) 513 if (oldAsset.Temporary)
367 { 514 {
368 scene.AssetService.Delete(oldID.ToString()); 515 scene.AssetService.Delete(oldID.ToString());
369 } 516 }
370 } 517 }
371 } 518 }
519
520 return asset.FullID;
372 } 521 }
373 522
374 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) 523 private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha)
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 56221aa..0b9174f 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -58,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
58 public string body; 58 public string body;
59 public int responseCode; 59 public int responseCode;
60 public string responseBody; 60 public string responseBody;
61 public string responseType = "text/plain";
61 //public ManualResetEvent ev; 62 //public ManualResetEvent ev;
62 public bool requestDone; 63 public bool requestDone;
63 public int startTime; 64 public int startTime;
@@ -270,6 +271,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
270 } 271 }
271 } 272 }
272 273
274 public void HttpContentType(UUID request, string type)
275 {
276 lock (m_UrlMap)
277 {
278 if (m_RequestMap.ContainsKey(request))
279 {
280 UrlData urlData = m_RequestMap[request];
281 urlData.requests[request].responseType = type;
282 }
283 else
284 {
285 m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString());
286 }
287 }
288 }
289
273 public void HttpResponse(UUID request, int status, string body) 290 public void HttpResponse(UUID request, int status, string body)
274 { 291 {
275 lock (m_RequestMap) 292 lock (m_RequestMap)
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
index 6f83948..45e6527 100644
--- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -32,6 +32,7 @@ using System.Net;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Imaging; 34using OpenMetaverse.Imaging;
35using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
35using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
37using log4net; 38using log4net;
@@ -67,12 +68,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
67 return true; 68 return true;
68 } 69 }
69 70
70 public byte[] ConvertUrl(string url, string extraParams) 71// public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
72// {
73// // We don't support conversion of body data.
74// return false;
75// }
76
77 public IDynamicTexture ConvertUrl(string url, string extraParams)
71 { 78 {
72 return null; 79 return null;
73 } 80 }
74 81
75 public byte[] ConvertStream(Stream data, string extraParams) 82 public IDynamicTexture ConvertData(string bodyData, string extraParams)
76 { 83 {
77 return null; 84 return null;
78 } 85 }
@@ -165,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
165 172
166 private void HttpRequestReturn(IAsyncResult result) 173 private void HttpRequestReturn(IAsyncResult result)
167 { 174 {
168
169 RequestState state = (RequestState) result.AsyncState; 175 RequestState state = (RequestState) result.AsyncState;
170 WebRequest request = (WebRequest) state.Request; 176 WebRequest request = (WebRequest) state.Request;
171 Stream stream = null; 177 Stream stream = null;
172 byte[] imageJ2000 = new byte[0]; 178 byte[] imageJ2000 = new byte[0];
179 Size newSize = new Size(0, 0);
173 180
174 try 181 try
175 { 182 {
@@ -182,37 +189,43 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
182 try 189 try
183 { 190 {
184 Bitmap image = new Bitmap(stream); 191 Bitmap image = new Bitmap(stream);
185 Size newsize;
186 192
187 // TODO: make this a bit less hard coded 193 // TODO: make this a bit less hard coded
188 if ((image.Height < 64) && (image.Width < 64)) 194 if ((image.Height < 64) && (image.Width < 64))
189 { 195 {
190 newsize = new Size(32, 32); 196 newSize.Width = 32;
197 newSize.Height = 32;
191 } 198 }
192 else if ((image.Height < 128) && (image.Width < 128)) 199 else if ((image.Height < 128) && (image.Width < 128))
193 { 200 {
194 newsize = new Size(64, 64); 201 newSize.Width = 64;
202 newSize.Height = 64;
195 } 203 }
196 else if ((image.Height < 256) && (image.Width < 256)) 204 else if ((image.Height < 256) && (image.Width < 256))
197 { 205 {
198 newsize = new Size(128, 128); 206 newSize.Width = 128;
207 newSize.Height = 128;
199 } 208 }
200 else if ((image.Height < 512 && image.Width < 512)) 209 else if ((image.Height < 512 && image.Width < 512))
201 { 210 {
202 newsize = new Size(256, 256); 211 newSize.Width = 256;
212 newSize.Height = 256;
203 } 213 }
204 else if ((image.Height < 1024 && image.Width < 1024)) 214 else if ((image.Height < 1024 && image.Width < 1024))
205 { 215 {
206 newsize = new Size(512, 512); 216 newSize.Width = 512;
217 newSize.Height = 512;
207 } 218 }
208 else 219 else
209 { 220 {
210 newsize = new Size(1024, 1024); 221 newSize.Width = 1024;
222 newSize.Height = 1024;
211 } 223 }
212 224
213 Bitmap resize = new Bitmap(image, newsize); 225 using (Bitmap resize = new Bitmap(image, newSize))
214 226 {
215 imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); 227 imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
228 }
216 } 229 }
217 catch (Exception) 230 catch (Exception)
218 { 231 {
@@ -227,7 +240,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
227 } 240 }
228 catch (WebException) 241 catch (WebException)
229 { 242 {
230
231 } 243 }
232 finally 244 finally
233 { 245 {
@@ -236,9 +248,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
236 stream.Close(); 248 stream.Close();
237 } 249 }
238 } 250 }
239 m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}", 251
252 m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
240 imageJ2000.Length, state.RequestID); 253 imageJ2000.Length, state.RequestID);
241 m_textureManager.ReturnData(state.RequestID, imageJ2000); 254
255 m_textureManager.ReturnData(
256 state.RequestID,
257 new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
258 request.RequestUri, null, imageJ2000, newSize, false));
242 } 259 }
243 260
244 #region Nested type: RequestState 261 #region Nested type: RequestState
diff --git a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
index 705a847..98396ff 100644
--- a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
@@ -130,13 +130,25 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
130 m_scriptModule.PostScriptEvent(script, "link_message", args); 130 m_scriptModule.PostScriptEvent(script, "link_message", args);
131 } 131 }
132 132
133 private static MethodInfo GetMethodInfoFromType(Type target, string meth, bool searchInstanceMethods)
134 {
135 BindingFlags getMethodFlags =
136 BindingFlags.NonPublic | BindingFlags.Public;
137
138 if (searchInstanceMethods)
139 getMethodFlags |= BindingFlags.Instance;
140 else
141 getMethodFlags |= BindingFlags.Static;
142
143 return target.GetMethod(meth, getMethodFlags);
144 }
145
133 public void RegisterScriptInvocation(object target, string meth) 146 public void RegisterScriptInvocation(object target, string meth)
134 { 147 {
135 MethodInfo mi = target.GetType().GetMethod(meth, 148 MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
136 BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
137 if (mi == null) 149 if (mi == null)
138 { 150 {
139 m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}",meth); 151 m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth);
140 return; 152 return;
141 } 153 }
142 154
@@ -151,38 +163,71 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
151 163
152 public void RegisterScriptInvocation(object target, MethodInfo mi) 164 public void RegisterScriptInvocation(object target, MethodInfo mi)
153 { 165 {
154 m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, target.GetType().Name); 166 m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
155 167
156 Type delegateType; 168 Type delegateType;
157 var typeArgs = mi.GetParameters() 169 List<Type> typeArgs = mi.GetParameters()
158 .Select(p => p.ParameterType) 170 .Select(p => p.ParameterType)
159 .ToList(); 171 .ToList();
160 172
161 if (mi.ReturnType == typeof(void)) 173 if (mi.ReturnType == typeof(void))
162 { 174 {
163 delegateType = Expression.GetActionType(typeArgs.ToArray()); 175 delegateType = Expression.GetActionType(typeArgs.ToArray());
164 } 176 }
165 else 177 else
166 { 178 {
167 typeArgs.Add(mi.ReturnType); 179 typeArgs.Add(mi.ReturnType);
168 delegateType = Expression.GetFuncType(typeArgs.ToArray()); 180 delegateType = Expression.GetFuncType(typeArgs.ToArray());
169 } 181 }
170 182
171 Delegate fcall = Delegate.CreateDelegate(delegateType, target, mi); 183 Delegate fcall;
184 if (!(target is Type))
185 fcall = Delegate.CreateDelegate(delegateType, target, mi);
186 else
187 fcall = Delegate.CreateDelegate(delegateType, (Type)target, mi.Name);
172 188
173 lock (m_scriptInvocation) 189 lock (m_scriptInvocation)
174 { 190 {
175 ParameterInfo[] parameters = fcall.Method.GetParameters (); 191 ParameterInfo[] parameters = fcall.Method.GetParameters();
176 if (parameters.Length < 2) // Must have two UUID params 192 if (parameters.Length < 2) // Must have two UUID params
177 return; 193 return;
178 194
179 // Hide the first two parameters 195 // Hide the first two parameters
180 Type[] parmTypes = new Type[parameters.Length - 2]; 196 Type[] parmTypes = new Type[parameters.Length - 2];
181 for (int i = 2 ; i < parameters.Length ; i++) 197 for (int i = 2; i < parameters.Length; i++)
182 parmTypes[i - 2] = parameters[i].ParameterType; 198 parmTypes[i - 2] = parameters[i].ParameterType;
183 m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType); 199 m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType);
184 } 200 }
185 } 201 }
202
203 public void RegisterScriptInvocation(Type target, string[] methods)
204 {
205 foreach (string method in methods)
206 {
207 MethodInfo mi = GetMethodInfoFromType(target, method, false);
208 if (mi == null)
209 m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", method);
210 else
211 RegisterScriptInvocation(target, mi);
212 }
213 }
214
215 public void RegisterScriptInvocations(IRegionModuleBase target)
216 {
217 foreach(MethodInfo method in target.GetType().GetMethods(
218 BindingFlags.Public | BindingFlags.Instance |
219 BindingFlags.Static))
220 {
221 if(method.GetCustomAttributes(
222 typeof(ScriptInvocationAttribute), true).Any())
223 {
224 if(method.IsStatic)
225 RegisterScriptInvocation(target.GetType(), method);
226 else
227 RegisterScriptInvocation(target, method);
228 }
229 }
230 }
186 231
187 public Delegate[] GetScriptInvocationList() 232 public Delegate[] GetScriptInvocationList()
188 { 233 {
@@ -285,6 +330,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
285 } 330 }
286 } 331 }
287 332
333 public void RegisterConstants(IRegionModuleBase target)
334 {
335 foreach (FieldInfo field in target.GetType().GetFields(
336 BindingFlags.Public | BindingFlags.Static |
337 BindingFlags.Instance))
338 {
339 if (field.GetCustomAttributes(
340 typeof(ScriptConstantAttribute), true).Any())
341 {
342 RegisterConstant(field.Name, field.GetValue(target));
343 }
344 }
345 }
346
288 /// <summary> 347 /// <summary>
289 /// Operation to check for a registered constant 348 /// Operation to check for a registered constant
290 /// </summary> 349 /// </summary>
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
index 9787c8c..41baccc 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
@@ -45,31 +45,292 @@ using OpenSim.Tests.Common.Mock;
45namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests 45namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
46{ 46{
47 [TestFixture] 47 [TestFixture]
48 public class VectorRenderModuleTests 48 public class VectorRenderModuleTests : OpenSimTestCase
49 { 49 {
50 Scene m_scene;
51 DynamicTextureModule m_dtm;
52 VectorRenderModule m_vrm;
53
54 private void SetupScene(bool reuseTextures)
55 {
56 m_scene = new SceneHelpers().SetupScene();
57
58 m_dtm = new DynamicTextureModule();
59 m_dtm.ReuseTextures = reuseTextures;
60// m_dtm.ReuseLowDataTextures = reuseTextures;
61
62 m_vrm = new VectorRenderModule();
63
64 SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm);
65 }
66
50 [Test] 67 [Test]
51 public void TestDraw() 68 public void TestDraw()
52 { 69 {
53 TestHelpers.InMethod(); 70 TestHelpers.InMethod();
54 71
55 Scene scene = new SceneHelpers().SetupScene(); 72 SetupScene(false);
56 DynamicTextureModule dtm = new DynamicTextureModule(); 73 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
57 VectorRenderModule vrm = new VectorRenderModule();
58 SceneHelpers.SetupSceneModules(scene, dtm, vrm);
59
60 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene);
61 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; 74 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
62 75
63 dtm.AddDynamicTextureData( 76 m_dtm.AddDynamicTextureData(
64 scene.RegionInfo.RegionID, 77 m_scene.RegionInfo.RegionID,
65 so.UUID, 78 so.UUID,
66 vrm.GetContentType(), 79 m_vrm.GetContentType(),
67 "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", 80 "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;",
68 "", 81 "",
69 0); 82 0);
70 83
84 Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
85 }
86
87 [Test]
88 public void TestRepeatSameDraw()
89 {
90 TestHelpers.InMethod();
91
92 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
93
94 SetupScene(false);
95 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
96
97 m_dtm.AddDynamicTextureData(
98 m_scene.RegionInfo.RegionID,
99 so.UUID,
100 m_vrm.GetContentType(),
101 dtText,
102 "",
103 0);
104
105 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
106
107 m_dtm.AddDynamicTextureData(
108 m_scene.RegionInfo.RegionID,
109 so.UUID,
110 m_vrm.GetContentType(),
111 dtText,
112 "",
113 0);
114
115 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
116 }
117
118 [Test]
119 public void TestRepeatSameDrawDifferentExtraParams()
120 {
121 TestHelpers.InMethod();
122
123 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
124
125 SetupScene(false);
126 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
127
128 m_dtm.AddDynamicTextureData(
129 m_scene.RegionInfo.RegionID,
130 so.UUID,
131 m_vrm.GetContentType(),
132 dtText,
133 "",
134 0);
135
136 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
137
138 m_dtm.AddDynamicTextureData(
139 m_scene.RegionInfo.RegionID,
140 so.UUID,
141 m_vrm.GetContentType(),
142 dtText,
143 "alpha:250",
144 0);
145
146 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
147 }
148
149 [Test]
150 public void TestRepeatSameDrawContainingImage()
151 {
152 TestHelpers.InMethod();
153
154 string dtText
155 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
156
157 SetupScene(false);
158 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
159
160 m_dtm.AddDynamicTextureData(
161 m_scene.RegionInfo.RegionID,
162 so.UUID,
163 m_vrm.GetContentType(),
164 dtText,
165 "",
166 0);
167
168 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
169
170 m_dtm.AddDynamicTextureData(
171 m_scene.RegionInfo.RegionID,
172 so.UUID,
173 m_vrm.GetContentType(),
174 dtText,
175 "",
176 0);
177
178 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
179 }
180
181 [Test]
182 public void TestDrawReusingTexture()
183 {
184 TestHelpers.InMethod();
185
186 SetupScene(true);
187 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
188 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
189
190 m_dtm.AddDynamicTextureData(
191 m_scene.RegionInfo.RegionID,
192 so.UUID,
193 m_vrm.GetContentType(),
194 "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;",
195 "",
196 0);
71 197
72 Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); 198 Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
73 } 199 }
200
201 [Test]
202 public void TestRepeatSameDrawReusingTexture()
203 {
204 TestHelpers.InMethod();
205// TestHelpers.EnableLogging();
206
207 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
208
209 SetupScene(true);
210 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
211
212 m_dtm.AddDynamicTextureData(
213 m_scene.RegionInfo.RegionID,
214 so.UUID,
215 m_vrm.GetContentType(),
216 dtText,
217 "",
218 0);
219
220 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
221
222 m_dtm.AddDynamicTextureData(
223 m_scene.RegionInfo.RegionID,
224 so.UUID,
225 m_vrm.GetContentType(),
226 dtText,
227 "",
228 0);
229
230 Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
231 }
232
233 /// <summary>
234 /// Test a low data dynamically generated texture such that it is treated as a low data texture that causes
235 /// problems for current viewers.
236 /// </summary>
237 /// <remarks>
238 /// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the
239 /// texture
240 /// </remarks>
241 [Test]
242 public void TestRepeatSameDrawLowDataTexture()
243 {
244 TestHelpers.InMethod();
245// TestHelpers.EnableLogging();
246
247 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
248
249 SetupScene(true);
250 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
251
252 m_dtm.AddDynamicTextureData(
253 m_scene.RegionInfo.RegionID,
254 so.UUID,
255 m_vrm.GetContentType(),
256 dtText,
257 "1024",
258 0);
259
260 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
261
262 m_dtm.AddDynamicTextureData(
263 m_scene.RegionInfo.RegionID,
264 so.UUID,
265 m_vrm.GetContentType(),
266 dtText,
267 "1024",
268 0);
269
270 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
271 }
272
273 [Test]
274 public void TestRepeatSameDrawDifferentExtraParamsReusingTexture()
275 {
276 TestHelpers.InMethod();
277
278 string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
279
280 SetupScene(true);
281 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
282
283 m_dtm.AddDynamicTextureData(
284 m_scene.RegionInfo.RegionID,
285 so.UUID,
286 m_vrm.GetContentType(),
287 dtText,
288 "",
289 0);
290
291 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
292
293 m_dtm.AddDynamicTextureData(
294 m_scene.RegionInfo.RegionID,
295 so.UUID,
296 m_vrm.GetContentType(),
297 dtText,
298 "alpha:250",
299 0);
300
301 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
302 }
303
304 [Test]
305 public void TestRepeatSameDrawContainingImageReusingTexture()
306 {
307 TestHelpers.InMethod();
308
309 string dtText
310 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png";
311
312 SetupScene(true);
313 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
314
315 m_dtm.AddDynamicTextureData(
316 m_scene.RegionInfo.RegionID,
317 so.UUID,
318 m_vrm.GetContentType(),
319 dtText,
320 "",
321 0);
322
323 UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
324
325 m_dtm.AddDynamicTextureData(
326 m_scene.RegionInfo.RegionID,
327 so.UUID,
328 m_vrm.GetContentType(),
329 dtText,
330 "",
331 0);
332
333 Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
334 }
74 } 335 }
75} \ No newline at end of file 336} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index 8b2f2f8..673c2d1 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -30,10 +30,12 @@ using System.Drawing;
30using System.Drawing.Imaging; 30using System.Drawing.Imaging;
31using System.Globalization; 31using System.Globalization;
32using System.IO; 32using System.IO;
33using System.Linq;
33using System.Net; 34using System.Net;
34using Nini.Config; 35using Nini.Config;
35using OpenMetaverse; 36using OpenMetaverse;
36using OpenMetaverse.Imaging; 37using OpenMetaverse.Imaging;
38using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
37using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
39using log4net; 41using log4net;
@@ -45,9 +47,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
45{ 47{
46 public class VectorRenderModule : IRegionModule, IDynamicTextureRender 48 public class VectorRenderModule : IRegionModule, IDynamicTextureRender
47 { 49 {
50 // These fields exist for testing purposes, please do not remove.
51// private static bool s_flipper;
52// private static byte[] s_asset1Data;
53// private static byte[] s_asset2Data;
54
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 56
50 private string m_name = "VectorRenderModule";
51 private Scene m_scene; 57 private Scene m_scene;
52 private IDynamicTextureManager m_textureManager; 58 private IDynamicTextureManager m_textureManager;
53 private Graphics m_graph; 59 private Graphics m_graph;
@@ -61,12 +67,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
61 67
62 public string GetContentType() 68 public string GetContentType()
63 { 69 {
64 return ("vector"); 70 return "vector";
65 } 71 }
66 72
67 public string GetName() 73 public string GetName()
68 { 74 {
69 return m_name; 75 return Name;
70 } 76 }
71 77
72 public bool SupportsAsynchronous() 78 public bool SupportsAsynchronous()
@@ -74,14 +80,20 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
74 return true; 80 return true;
75 } 81 }
76 82
77 public byte[] ConvertUrl(string url, string extraParams) 83// public bool AlwaysIdenticalConversion(string bodyData, string extraParams)
84// {
85// string[] lines = GetLines(bodyData);
86// return lines.Any((str, r) => str.StartsWith("Image"));
87// }
88
89 public IDynamicTexture ConvertUrl(string url, string extraParams)
78 { 90 {
79 return null; 91 return null;
80 } 92 }
81 93
82 public byte[] ConvertStream(Stream data, string extraParams) 94 public IDynamicTexture ConvertData(string bodyData, string extraParams)
83 { 95 {
84 return null; 96 return Draw(bodyData, extraParams);
85 } 97 }
86 98
87 public bool AsyncConvertUrl(UUID id, string url, string extraParams) 99 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
@@ -91,21 +103,28 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
91 103
92 public bool AsyncConvertData(UUID id, string bodyData, string extraParams) 104 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
93 { 105 {
94 Draw(bodyData, id, extraParams); 106 // XXX: This isn't actually being done asynchronously!
107 m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams));
108
95 return true; 109 return true;
96 } 110 }
97 111
98 public void GetDrawStringSize(string text, string fontName, int fontSize, 112 public void GetDrawStringSize(string text, string fontName, int fontSize,
99 out double xSize, out double ySize) 113 out double xSize, out double ySize)
100 { 114 {
101 using (Font myFont = new Font(fontName, fontSize)) 115 lock (this)
102 { 116 {
103 SizeF stringSize = new SizeF(); 117 using (Font myFont = new Font(fontName, fontSize))
104 lock (m_graph)
105 { 118 {
106 stringSize = m_graph.MeasureString(text, myFont); 119 SizeF stringSize = new SizeF();
107 xSize = stringSize.Width; 120
108 ySize = stringSize.Height; 121 // XXX: This lock may be unnecessary.
122 lock (m_graph)
123 {
124 stringSize = m_graph.MeasureString(text, myFont);
125 xSize = stringSize.Width;
126 ySize = stringSize.Height;
127 }
109 } 128 }
110 } 129 }
111 } 130 }
@@ -144,6 +163,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
144 { 163 {
145 m_textureManager.RegisterRender(GetContentType(), this); 164 m_textureManager.RegisterRender(GetContentType(), this);
146 } 165 }
166
167 // This code exists for testing purposes, please do not remove.
168// s_asset1Data = m_scene.AssetService.Get("00000000-0000-1111-9999-000000000001").Data;
169// s_asset1Data = m_scene.AssetService.Get("9f4acf0d-1841-4e15-bdb8-3a12efc9dd8f").Data;
170
171 // Terrain dirt - smallest bin/assets file (6004 bytes)
172// s_asset2Data = m_scene.AssetService.Get("b8d3965a-ad78-bf43-699b-bff8eca6c975").Data;
147 } 173 }
148 174
149 public void Close() 175 public void Close()
@@ -152,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
152 178
153 public string Name 179 public string Name
154 { 180 {
155 get { return m_name; } 181 get { return "VectorRenderModule"; }
156 } 182 }
157 183
158 public bool IsSharedModule 184 public bool IsSharedModule
@@ -162,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
162 188
163 #endregion 189 #endregion
164 190
165 private void Draw(string data, UUID id, string extraParams) 191 private IDynamicTexture Draw(string data, string extraParams)
166 { 192 {
167 // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha 193 // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
168 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 194 // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
@@ -305,40 +331,57 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
305 331
306 Bitmap bitmap = null; 332 Bitmap bitmap = null;
307 Graphics graph = null; 333 Graphics graph = null;
334 bool reuseable = false;
308 335
309 try 336 try
310 { 337 {
311 if (alpha == 256) 338 // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
312 bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); 339 // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
313 else 340 // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
314 bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); 341 // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
315 342 // under lock.
316 graph = Graphics.FromImage(bitmap); 343 lock (this)
317
318 // this is really just to save people filling the
319 // background color in their scripts, only do when fully opaque
320 if (alpha >= 255)
321 { 344 {
322 using (SolidBrush bgFillBrush = new SolidBrush(bgColor)) 345 if (alpha == 256)
346 bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
347 else
348 bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
349
350 graph = Graphics.FromImage(bitmap);
351
352 // this is really just to save people filling the
353 // background color in their scripts, only do when fully opaque
354 if (alpha >= 255)
323 { 355 {
324 graph.FillRectangle(bgFillBrush, 0, 0, width, height); 356 using (SolidBrush bgFillBrush = new SolidBrush(bgColor))
357 {
358 graph.FillRectangle(bgFillBrush, 0, 0, width, height);
359 }
325 } 360 }
326 } 361
327 362 for (int w = 0; w < bitmap.Width; w++)
328 for (int w = 0; w < bitmap.Width; w++)
329 {
330 if (alpha <= 255)
331 { 363 {
332 for (int h = 0; h < bitmap.Height; h++) 364 if (alpha <= 255)
333 { 365 {
334 bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); 366 for (int h = 0; h < bitmap.Height; h++)
367 {
368 bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h)));
369 }
335 } 370 }
336 } 371 }
372
373 GDIDraw(data, graph, altDataDelim, out reuseable);
337 } 374 }
338 375
339 GDIDraw(data, graph, altDataDelim);
340
341 byte[] imageJ2000 = new byte[0]; 376 byte[] imageJ2000 = new byte[0];
377
378 // This code exists for testing purposes, please do not remove.
379// if (s_flipper)
380// imageJ2000 = s_asset1Data;
381// else
382// imageJ2000 = s_asset2Data;
383//
384// s_flipper = !s_flipper;
342 385
343 try 386 try
344 { 387 {
@@ -351,15 +394,24 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
351 e.Message, e.StackTrace); 394 e.Message, e.StackTrace);
352 } 395 }
353 396
354 m_textureManager.ReturnData(id, imageJ2000); 397 return new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
398 data, extraParams, imageJ2000, new Size(width, height), reuseable);
355 } 399 }
356 finally 400 finally
357 { 401 {
358 if (graph != null) 402 // XXX: In testing, it appears that if multiple threads dispose of separate GDI+ objects simultaneously,
359 graph.Dispose(); 403 // the native malloc heap can become corrupted, possibly due to a double free(). This may be due to
360 404 // bugs in the underlying libcairo used by mono's libgdiplus.dll on Linux/OSX. These problems were
361 if (bitmap != null) 405 // seen with both libcario 1.10.2-6.1ubuntu3 and 1.8.10-2ubuntu1. They go away if disposal is perfomed
362 bitmap.Dispose(); 406 // under lock.
407 lock (this)
408 {
409 if (graph != null)
410 graph.Dispose();
411
412 if (bitmap != null)
413 bitmap.Dispose();
414 }
363 } 415 }
364 } 416 }
365 417
@@ -418,8 +470,21 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
418 } 470 }
419*/ 471*/
420 472
421 private void GDIDraw(string data, Graphics graph, char dataDelim) 473 /// <summary>
474 /// Split input data into discrete command lines.
475 /// </summary>
476 /// <returns></returns>
477 /// <param name='data'></param>
478 /// <param name='dataDelim'></param>
479 private string[] GetLines(string data, char dataDelim)
480 {
481 char[] lineDelimiter = { dataDelim };
482 return data.Split(lineDelimiter);
483 }
484
485 private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable)
422 { 486 {
487 reuseable = true;
423 Point startPoint = new Point(0, 0); 488 Point startPoint = new Point(0, 0);
424 Point endPoint = new Point(0, 0); 489 Point endPoint = new Point(0, 0);
425 Pen drawPen = null; 490 Pen drawPen = null;
@@ -434,11 +499,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
434 myFont = new Font(fontName, fontSize); 499 myFont = new Font(fontName, fontSize);
435 myBrush = new SolidBrush(Color.Black); 500 myBrush = new SolidBrush(Color.Black);
436 501
437 char[] lineDelimiter = {dataDelim};
438 char[] partsDelimiter = {','}; 502 char[] partsDelimiter = {','};
439 string[] lines = data.Split(lineDelimiter);
440 503
441 foreach (string line in lines) 504 foreach (string line in GetLines(data, dataDelim))
442 { 505 {
443 string nextLine = line.Trim(); 506 string nextLine = line.Trim();
444 //replace with switch, or even better, do some proper parsing 507 //replace with switch, or even better, do some proper parsing
@@ -469,6 +532,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
469 } 532 }
470 else if (nextLine.StartsWith("Image")) 533 else if (nextLine.StartsWith("Image"))
471 { 534 {
535 // We cannot reuse any generated texture involving fetching an image via HTTP since that image
536 // can change.
537 reuseable = false;
538
472 float x = 0; 539 float x = 0;
473 float y = 0; 540 float y = 0;
474 GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); 541 GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
index 008465f..1e1c7d0 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
@@ -56,6 +56,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
56 56
57 private bool m_Enabled = false; 57 private bool m_Enabled = false;
58 58
59 private AssetPermissions m_AssetPerms;
60
59 public Type ReplaceableInterface 61 public Type ReplaceableInterface
60 { 62 {
61 get { return null; } 63 get { return null; }
@@ -128,6 +130,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
128 if (m_LocalAssetServiceURI != string.Empty) 130 if (m_LocalAssetServiceURI != string.Empty)
129 m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/'); 131 m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
130 132
133 IConfig hgConfig = source.Configs["HGAssetService"];
134 m_AssetPerms = new AssetPermissions(hgConfig); // it's ok if arg is null
135
131 m_Enabled = true; 136 m_Enabled = true;
132 m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); 137 m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
133 } 138 }
@@ -206,14 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
206 asset = m_HGService.Get(id); 211 asset = m_HGService.Get(id);
207 if (asset != null) 212 if (asset != null)
208 { 213 {
209 // Now store it locally 214 // Now store it locally, if allowed
210 // For now, let me just do it for textures and scripts 215 if (m_AssetPerms.AllowedImport(asset.Type))
211 if (((AssetType)asset.Type == AssetType.Texture) ||
212 ((AssetType)asset.Type == AssetType.LSLBytecode) ||
213 ((AssetType)asset.Type == AssetType.LSLText))
214 {
215 m_GridService.Store(asset); 216 m_GridService.Store(asset);
216 } 217 else
218 return null;
217 } 219 }
218 } 220 }
219 else 221 else
@@ -328,7 +330,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
328 330
329 string id = string.Empty; 331 string id = string.Empty;
330 if (IsHG(asset.ID)) 332 if (IsHG(asset.ID))
331 id = m_HGService.Store(asset); 333 {
334 if (m_AssetPerms.AllowedExport(asset.Type))
335 id = m_HGService.Store(asset);
336 else
337 return String.Empty;
338 }
332 else 339 else
333 id = m_GridService.Store(asset); 340 id = m_GridService.Store(asset);
334 341
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
index c78915f..449c1f1 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
@@ -204,8 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
204 public byte[] GetData(string id) 204 public byte[] GetData(string id)
205 { 205 {
206// m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id); 206// m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id);
207 207
208 AssetBase asset = m_Cache.Get(id); 208 AssetBase asset = null;
209
210 if (m_Cache != null)
211 asset = m_Cache.Get(id);
209 212
210 if (asset != null) 213 if (asset != null)
211 return asset.Data; 214 return asset.Data;
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs
new file mode 100644
index 0000000..1982473
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs
@@ -0,0 +1,136 @@
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.IO;
31using System.Reflection;
32using System.Threading;
33using log4net.Config;
34using Nini.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset;
40using OpenSim.Tests.Common;
41
42namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
43{
44 [TestFixture]
45 public class AssetConnectorsTests : OpenSimTestCase
46 {
47 [Test]
48 public void TestAddAsset()
49 {
50 TestHelpers.InMethod();
51// TestHelpers.EnableLogging();
52
53 IConfigSource config = new IniConfigSource();
54 config.AddConfig("Modules");
55 config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
56 config.AddConfig("AssetService");
57 config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
58 config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
59
60 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
61 lasc.Initialise(config);
62
63 AssetBase a1 = AssetHelpers.CreateNotecardAsset();
64 lasc.Store(a1);
65
66 AssetBase retreivedA1 = lasc.Get(a1.ID);
67 Assert.That(retreivedA1.ID, Is.EqualTo(a1.ID));
68 Assert.That(retreivedA1.Metadata.ID, Is.EqualTo(a1.Metadata.ID));
69 Assert.That(retreivedA1.Data.Length, Is.EqualTo(a1.Data.Length));
70
71 AssetMetadata retrievedA1Metadata = lasc.GetMetadata(a1.ID);
72 Assert.That(retrievedA1Metadata.ID, Is.EqualTo(a1.ID));
73
74 byte[] retrievedA1Data = lasc.GetData(a1.ID);
75 Assert.That(retrievedA1Data.Length, Is.EqualTo(a1.Data.Length));
76
77 // TODO: Add cache and check that this does receive a copy of the asset
78 }
79
80 [Test]
81 public void TestAddTemporaryAsset()
82 {
83 TestHelpers.InMethod();
84// TestHelpers.EnableLogging();
85
86 IConfigSource config = new IniConfigSource();
87 config.AddConfig("Modules");
88 config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
89 config.AddConfig("AssetService");
90 config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
91 config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
92
93 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
94 lasc.Initialise(config);
95
96 AssetBase a1 = AssetHelpers.CreateNotecardAsset();
97 a1.Temporary = true;
98
99 lasc.Store(a1);
100
101 Assert.That(lasc.Get(a1.ID), Is.Null);
102 Assert.That(lasc.GetData(a1.ID), Is.Null);
103 Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
104
105 // TODO: Add cache and check that this does receive a copy of the asset
106 }
107
108 [Test]
109 public void TestAddLocalAsset()
110 {
111 TestHelpers.InMethod();
112// TestHelpers.EnableLogging();
113
114 IConfigSource config = new IniConfigSource();
115 config.AddConfig("Modules");
116 config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
117 config.AddConfig("AssetService");
118 config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
119 config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
120
121 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
122 lasc.Initialise(config);
123
124 AssetBase a1 = AssetHelpers.CreateNotecardAsset();
125 a1.Local = true;
126
127 lasc.Store(a1);
128
129 Assert.That(lasc.Get(a1.ID), Is.Null);
130 Assert.That(lasc.GetData(a1.ID), Is.Null);
131 Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
132
133 // TODO: Add cache and check that this does receive a copy of the asset
134 }
135 }
136} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index b286d17..4338133 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -43,11 +43,15 @@ using OpenSim.Tests.Common;
43namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests 43namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
44{ 44{
45 [TestFixture] 45 [TestFixture]
46 public class GridConnectorsTests 46 public class GridConnectorsTests : OpenSimTestCase
47 { 47 {
48 LocalGridServicesConnector m_LocalConnector; 48 LocalGridServicesConnector m_LocalConnector;
49 private void SetUp() 49
50 [SetUp]
51 public override void SetUp()
50 { 52 {
53 base.SetUp();
54
51 IConfigSource config = new IniConfigSource(); 55 IConfigSource config = new IniConfigSource();
52 config.AddConfig("Modules"); 56 config.AddConfig("Modules");
53 config.AddConfig("GridService"); 57 config.AddConfig("GridService");
@@ -71,8 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
71 TestHelpers.InMethod(); 75 TestHelpers.InMethod();
72// log4net.Config.XmlConfigurator.Configure(); 76// log4net.Config.XmlConfigurator.Configure();
73 77
74 SetUp();
75
76 // Create 4 regions 78 // Create 4 regions
77 GridRegion r1 = new GridRegion(); 79 GridRegion r1 = new GridRegion();
78 r1.RegionName = "Test Region 1"; 80 r1.RegionName = "Test Region 1";
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
index b0edce7..221f815 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
@@ -65,11 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
65 65
66 public void OnMakeRootAgent(ScenePresence sp) 66 public void OnMakeRootAgent(ScenePresence sp)
67 { 67 {
68// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
69
70 if (sp.PresenceType != PresenceType.Npc) 68 if (sp.PresenceType != PresenceType.Npc)
69 {
70 string userid = sp.Scene.UserManagementModule.GetUserUUI(sp.UUID);
71 //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName);
71 m_GridUserService.SetLastPosition( 72 m_GridUserService.SetLastPosition(
72 sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); 73 userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
74 }
73 } 75 }
74 76
75 public void OnNewClient(IClientAPI client) 77 public void OnNewClient(IClientAPI client)
@@ -82,9 +84,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
82 if (client.SceneAgent.IsChildAgent) 84 if (client.SceneAgent.IsChildAgent)
83 return; 85 return;
84 86
85// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); 87 string userId = client.AgentId.ToString();
88 if (client.Scene is Scene)
89 {
90 Scene s = (Scene)client.Scene;
91 userId = s.UserManagementModule.GetUserUUI(client.AgentId);
92 }
93 //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", userId, client.Scene.RegionInfo.RegionName);
94
86 m_GridUserService.LoggedOut( 95 m_GridUserService.LoggedOut(
87 client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, 96 userId, client.SessionId, client.Scene.RegionInfo.RegionID,
88 client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat); 97 client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
89 } 98 }
90 } 99 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/RemoteGridUserServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/RemoteGridUserServiceConnector.cs
index badb552..04acf67 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/RemoteGridUserServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/RemoteGridUserServiceConnector.cs
@@ -44,6 +44,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 private const int KEEPTIME = 30; // 30 secs
48 private ExpiringCache<string, GridUserInfo> m_Infos = new ExpiringCache<string, GridUserInfo>();
49
47 #region ISharedRegionModule 50 #region ISharedRegionModule
48 51
49 private bool m_Enabled = false; 52 private bool m_Enabled = false;
@@ -128,23 +131,60 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
128 131
129 public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat) 132 public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat)
130 { 133 {
134 if (m_Infos.Contains(userID))
135 m_Infos.Remove(userID);
136
131 return m_RemoteConnector.LoggedOut(userID, sessionID, region, position, lookat); 137 return m_RemoteConnector.LoggedOut(userID, sessionID, region, position, lookat);
132 } 138 }
133 139
134 140
135 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) 141 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
136 { 142 {
137 return m_RemoteConnector.SetHome(userID, regionID, position, lookAt); 143 if (m_RemoteConnector.SetHome(userID, regionID, position, lookAt))
144 {
145 // Update the cache too
146 GridUserInfo info = null;
147 if (m_Infos.TryGetValue(userID, out info))
148 {
149 info.HomeRegionID = regionID;
150 info.HomePosition = position;
151 info.HomeLookAt = lookAt;
152 }
153 return true;
154 }
155
156 return false;
138 } 157 }
139 158
140 public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 159 public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt)
141 { 160 {
142 return m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt); 161 if (m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt))
162 {
163 // Update the cache too
164 GridUserInfo info = null;
165 if (m_Infos.TryGetValue(userID, out info))
166 {
167 info.LastRegionID = regionID;
168 info.LastPosition = position;
169 info.LastLookAt = lookAt;
170 }
171 return true;
172 }
173
174 return false;
143 } 175 }
144 176
145 public GridUserInfo GetGridUserInfo(string userID) 177 public GridUserInfo GetGridUserInfo(string userID)
146 { 178 {
147 return m_RemoteConnector.GetGridUserInfo(userID); 179 GridUserInfo info = null;
180 if (m_Infos.TryGetValue(userID, out info))
181 return info;
182
183 info = m_RemoteConnector.GetGridUserInfo(userID);
184
185 m_Infos.AddOrUpdate(userID, info, KEEPTIME);
186
187 return info;
148 } 188 }
149 189
150 public GridUserInfo[] GetGridUserInfo(string[] userID) 190 public GridUserInfo[] GetGridUserInfo(string[] userID)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index 6eb99ea..8ed1833 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -313,7 +313,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
313 313
314 if (m_scenes.ContainsKey(destination.RegionID)) 314 if (m_scenes.ContainsKey(destination.RegionID))
315 { 315 {
316 Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id); }); 316// m_log.DebugFormat(
317// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
318// s.RegionInfo.RegionName, destination.RegionHandle);
319
320 Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); });
317 return true; 321 return true;
318 } 322 }
319 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); 323 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index 619550c..2127f4d 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 44using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
46using System.Threading;
46 47
47namespace OpenSim.Region.CoreModules.World.Archiver 48namespace OpenSim.Region.CoreModules.World.Archiver
48{ 49{
@@ -52,7 +53,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
52 public class ArchiveReadRequest 53 public class ArchiveReadRequest
53 { 54 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 /// <summary>
58 /// Contains data used while dearchiving a single scene.
59 /// </summary>
60 private class DearchiveContext
61 {
62 public Scene Scene { get; set; }
63
64 public List<string> SerialisedSceneObjects { get; set; }
65
66 public List<string> SerialisedParcels { get; set; }
67
68 public List<SceneObjectGroup> SceneObjects { get; set; }
69
70 public DearchiveContext(Scene scene)
71 {
72 Scene = scene;
73 SerialisedSceneObjects = new List<string>();
74 SerialisedParcels = new List<string>();
75 SceneObjects = new List<SceneObjectGroup>();
76 }
77 }
55 78
79
56 /// <summary> 80 /// <summary>
57 /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version 81 /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version
58 /// bumps here should be compatible. 82 /// bumps here should be compatible.
@@ -62,9 +86,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
62 /// <summary> 86 /// <summary>
63 /// Has the control file been loaded for this archive? 87 /// Has the control file been loaded for this archive?
64 /// </summary> 88 /// </summary>
65 public bool ControlFileLoaded { get; private set; } 89 public bool ControlFileLoaded { get; private set; }
66 90
67 protected Scene m_scene; 91 protected string m_loadPath;
92 protected Scene m_rootScene;
68 protected Stream m_loadStream; 93 protected Stream m_loadStream;
69 protected Guid m_requestId; 94 protected Guid m_requestId;
70 protected string m_errorMessage; 95 protected string m_errorMessage;
@@ -91,16 +116,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
91 { 116 {
92 if (m_UserMan == null) 117 if (m_UserMan == null)
93 { 118 {
94 m_UserMan = m_scene.RequestModuleInterface<IUserManagement>(); 119 m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>();
95 } 120 }
96 return m_UserMan; 121 return m_UserMan;
97 } 122 }
98 } 123 }
99 124
125 /// <summary>
126 /// Used to cache lookups for valid groups.
127 /// </summary>
128 private IDictionary<UUID, bool> m_validGroupUuids = new Dictionary<UUID, bool>();
129
130 private IGroupsModule m_groupsModule;
131
132 private IAssetService m_assetService = null;
133
134
100 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) 135 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId)
101 { 136 {
102 m_scene = scene; 137 m_rootScene = scene;
103 138
139 m_loadPath = loadPath;
104 try 140 try
105 { 141 {
106 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); 142 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress);
@@ -120,11 +156,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
120 156
121 // Zero can never be a valid user id 157 // Zero can never be a valid user id
122 m_validUserUuids[UUID.Zero] = false; 158 m_validUserUuids[UUID.Zero] = false;
159
160 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
161 m_assetService = m_rootScene.AssetService;
123 } 162 }
124 163
125 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) 164 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId)
126 { 165 {
127 m_scene = scene; 166 m_rootScene = scene;
167 m_loadPath = null;
128 m_loadStream = loadStream; 168 m_loadStream = loadStream;
129 m_merge = merge; 169 m_merge = merge;
130 m_skipAssets = skipAssets; 170 m_skipAssets = skipAssets;
@@ -132,6 +172,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
132 172
133 // Zero can never be a valid user id 173 // Zero can never be a valid user id
134 m_validUserUuids[UUID.Zero] = false; 174 m_validUserUuids[UUID.Zero] = false;
175
176 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
177 m_assetService = m_rootScene.AssetService;
135 } 178 }
136 179
137 /// <summary> 180 /// <summary>
@@ -139,25 +182,25 @@ namespace OpenSim.Region.CoreModules.World.Archiver
139 /// </summary> 182 /// </summary>
140 public void DearchiveRegion() 183 public void DearchiveRegion()
141 { 184 {
142 // The same code can handle dearchiving 0.1 and 0.2 OpenSim Archive versions
143 DearchiveRegion0DotStar();
144 }
145
146 private void DearchiveRegion0DotStar()
147 {
148 int successfulAssetRestores = 0; 185 int successfulAssetRestores = 0;
149 int failedAssetRestores = 0; 186 int failedAssetRestores = 0;
150 List<string> serialisedSceneObjects = new List<string>();
151 List<string> serialisedParcels = new List<string>();
152 string filePath = "NONE";
153 187
154 TarArchiveReader archive = new TarArchiveReader(m_loadStream); 188 DearchiveScenesInfo dearchivedScenes;
189
190 // We dearchive all the scenes at once, because the files in the TAR archive might be mixed.
191 // Therefore, we have to keep track of the dearchive context of all the scenes.
192 Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>();
193
194 string fullPath = "NONE";
195 TarArchiveReader archive = null;
155 byte[] data; 196 byte[] data;
156 TarArchiveReader.TarEntryType entryType; 197 TarArchiveReader.TarEntryType entryType;
157 198
158 try 199 try
159 { 200 {
160 while ((data = archive.ReadEntry(out filePath, out entryType)) != null) 201 FindAndLoadControlFile(out archive, out dearchivedScenes);
202
203 while ((data = archive.ReadEntry(out fullPath, out entryType)) != null)
161 { 204 {
162 //m_log.DebugFormat( 205 //m_log.DebugFormat(
163 // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); 206 // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length);
@@ -165,9 +208,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
165 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) 208 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
166 continue; 209 continue;
167 210
211
212 // Find the scene that this file belongs to
213
214 Scene scene;
215 string filePath;
216 if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath))
217 continue; // this file belongs to a region that we're not loading
218
219 DearchiveContext sceneContext = null;
220 if (scene != null)
221 {
222 if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext))
223 {
224 sceneContext = new DearchiveContext(scene);
225 sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext);
226 }
227 }
228
229
230 // Process the file
231
168 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) 232 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
169 { 233 {
170 serialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); 234 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
171 } 235 }
172 else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) 236 else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets)
173 { 237 {
@@ -181,19 +245,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver
181 } 245 }
182 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) 246 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
183 { 247 {
184 LoadTerrain(filePath, data); 248 LoadTerrain(scene, filePath, data);
185 } 249 }
186 else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) 250 else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
187 { 251 {
188 LoadRegionSettings(filePath, data); 252 LoadRegionSettings(scene, filePath, data, dearchivedScenes);
189 } 253 }
190 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) 254 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH))
191 { 255 {
192 serialisedParcels.Add(Encoding.UTF8.GetString(data)); 256 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
193 } 257 }
194 else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) 258 else if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
195 { 259 {
196 LoadControlFile(filePath, data); 260 // Ignore, because we already read the control file
197 } 261 }
198 } 262 }
199 263
@@ -201,15 +265,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
201 } 265 }
202 catch (Exception e) 266 catch (Exception e)
203 { 267 {
204 m_log.ErrorFormat( 268 m_log.Error(
205 "[ARCHIVER]: Aborting load with error in archive file {0}. {1}", filePath, e); 269 String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e);
206 m_errorMessage += e.ToString(); 270 m_errorMessage += e.ToString();
207 m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); 271 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
208 return; 272 return;
209 } 273 }
210 finally 274 finally
211 { 275 {
212 archive.Close(); 276 if (archive != null)
277 archive.Close();
213 } 278 }
214 279
215 if (!m_skipAssets) 280 if (!m_skipAssets)
@@ -223,32 +288,143 @@ namespace OpenSim.Region.CoreModules.World.Archiver
223 } 288 }
224 } 289 }
225 290
226 if (!m_merge) 291 foreach (DearchiveContext sceneContext in sceneContexts.Values)
227 { 292 {
228 m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); 293 m_log.InfoFormat("[ARCHIVER:] Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
229 m_scene.DeleteAllSceneObjects(); 294
295 if (!m_merge)
296 {
297 m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
298 sceneContext.Scene.DeleteAllSceneObjects();
299 }
300
301 try
302 {
303 LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels);
304 LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects);
305
306 // Inform any interested parties that the region has changed. We waited until now so that all
307 // of the region's objects will be loaded when we send this notification.
308 IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>();
309 if (estateModule != null)
310 estateModule.TriggerRegionInfoChange();
311 }
312 catch (Exception e)
313 {
314 m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e);
315 m_errorMessage += e.ToString();
316 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
317 return;
318 }
230 } 319 }
231 320
232 LoadParcels(serialisedParcels); 321 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
233 LoadObjects(serialisedSceneObjects); 322 // that users can enter the scene. If we allow the scripts to start in the loop above
323 // then they significantly increase the time until the OAR finishes loading.
324 Util.FireAndForget(delegate(object o)
325 {
326 Thread.Sleep(15000);
327 m_log.Info("Starting scripts in scene objects");
328
329 foreach (DearchiveContext sceneContext in sceneContexts.Values)
330 {
331 foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects)
332 {
333 sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart
334 sceneObject.ResumeScripts();
335 }
336
337 sceneContext.SceneObjects.Clear();
338 }
339 });
234 340
235 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); 341 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
236 342
237 m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); 343 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage);
344 }
345
346 /// <summary>
347 /// Searches through the files in the archive for the control file, and reads it.
348 /// We must read the control file first, in order to know which regions are available.
349 /// </summary>
350 /// <remarks>
351 /// In most cases the control file *is* first, since that's how we create archives. However,
352 /// it's possible that someone rewrote the archive externally so we can't rely on this fact.
353 /// </remarks>
354 /// <param name="archive"></param>
355 /// <param name="dearchivedScenes"></param>
356 private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes)
357 {
358 archive = new TarArchiveReader(m_loadStream);
359 dearchivedScenes = new DearchiveScenesInfo();
360
361 string filePath;
362 byte[] data;
363 TarArchiveReader.TarEntryType entryType;
364 bool firstFile = true;
365
366 while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
367 {
368 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
369 continue;
370
371 if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
372 {
373 LoadControlFile(filePath, data, dearchivedScenes);
374
375 // Find which scenes are available in the simulator
376 ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup();
377 SceneManager.Instance.ForEachScene(delegate(Scene scene2)
378 {
379 simulatorScenes.AddScene(scene2);
380 });
381 simulatorScenes.CalcSceneLocations();
382 dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes);
383
384 // If the control file wasn't the first file then reset the read pointer
385 if (!firstFile)
386 {
387 m_log.Warn("Control file wasn't the first file in the archive");
388 if (m_loadStream.CanSeek)
389 {
390 m_loadStream.Seek(0, SeekOrigin.Begin);
391 }
392 else if (m_loadPath != null)
393 {
394 archive.Close();
395 archive = null;
396 m_loadStream.Close();
397 m_loadStream = null;
398 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress);
399 archive = new TarArchiveReader(m_loadStream);
400 }
401 else
402 {
403 // There isn't currently a scenario where this happens, but it's best to add a check just in case
404 throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking");
405 }
406 }
407
408 return;
409 }
410
411 firstFile = false;
412 }
413
414 throw new Exception("Control file not found");
238 } 415 }
239 416
240 /// <summary> 417 /// <summary>
241 /// Load serialized scene objects. 418 /// Load serialized scene objects.
242 /// </summary> 419 /// </summary>
243 /// <param name="serialisedSceneObjects"></param> 420 protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects)
244 protected void LoadObjects(List<string> serialisedSceneObjects)
245 { 421 {
246 // Reload serialized prims 422 // Reload serialized prims
247 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); 423 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
248 424
249 UUID oldTelehubUUID = m_scene.RegionInfo.RegionSettings.TelehubObject; 425 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
250 426
251 IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface<IRegionSerialiserModule>(); 427 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
252 int sceneObjectsLoadedCount = 0; 428 int sceneObjectsLoadedCount = 0;
253 429
254 foreach (string serialisedSceneObject in serialisedSceneObjects) 430 foreach (string serialisedSceneObject in serialisedSceneObjects)
@@ -269,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
269 445
270 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); 446 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
271 447
272 bool isTelehub = (sceneObject.UUID == oldTelehubUUID); 448 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
273 449
274 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned 450 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
275 // on the same region server and multiple examples a single object archive to be imported 451 // on the same region server and multiple examples a single object archive to be imported
@@ -279,8 +455,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
279 if (isTelehub) 455 if (isTelehub)
280 { 456 {
281 // Change the Telehub Object to the new UUID 457 // Change the Telehub Object to the new UUID
282 m_scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; 458 scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID;
283 m_scene.RegionInfo.RegionSettings.Save(); 459 scene.RegionInfo.RegionSettings.Save();
284 oldTelehubUUID = UUID.Zero; 460 oldTelehubUUID = UUID.Zero;
285 } 461 }
286 462
@@ -290,17 +466,20 @@ namespace OpenSim.Region.CoreModules.World.Archiver
290 { 466 {
291 if (part.CreatorData == null || part.CreatorData == string.Empty) 467 if (part.CreatorData == null || part.CreatorData == string.Empty)
292 { 468 {
293 if (!ResolveUserUuid(part.CreatorID)) 469 if (!ResolveUserUuid(scene, part.CreatorID))
294 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 470 part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
295 } 471 }
296 if (UserManager != null) 472 if (UserManager != null)
297 UserManager.AddUser(part.CreatorID, part.CreatorData); 473 UserManager.AddUser(part.CreatorID, part.CreatorData);
298 474
299 if (!ResolveUserUuid(part.OwnerID)) 475 if (!ResolveUserUuid(scene, part.OwnerID))
300 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 476 part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
477
478 if (!ResolveUserUuid(scene, part.LastOwnerID))
479 part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
301 480
302 if (!ResolveUserUuid(part.LastOwnerID)) 481 if (!ResolveGroupUuid(part.GroupID))
303 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 482 part.GroupID = UUID.Zero;
304 483
305 // And zap any troublesome sit target information 484 // And zap any troublesome sit target information
306// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); 485// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
@@ -311,14 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
311 // being no copy/no mod for everyone 490 // being no copy/no mod for everyone
312 lock (part.TaskInventory) 491 lock (part.TaskInventory)
313 { 492 {
314 if (!ResolveUserUuid(part.CreatorID)) 493 if (!ResolveUserUuid(scene, part.CreatorID))
315 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 494 part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
316 495
317 if (!ResolveUserUuid(part.OwnerID)) 496 if (!ResolveUserUuid(scene, part.OwnerID))
318 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 497 part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
319 498
320 if (!ResolveUserUuid(part.LastOwnerID)) 499 if (!ResolveUserUuid(scene, part.LastOwnerID))
321 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 500 part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
322 501
323 // And zap any troublesome sit target information 502 // And zap any troublesome sit target information
324 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); 503 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
@@ -331,26 +510,31 @@ namespace OpenSim.Region.CoreModules.World.Archiver
331 TaskInventoryDictionary inv = part.TaskInventory; 510 TaskInventoryDictionary inv = part.TaskInventory;
332 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 511 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
333 { 512 {
334 if (!ResolveUserUuid(kvp.Value.OwnerID)) 513 if (!ResolveUserUuid(scene, kvp.Value.OwnerID))
335 { 514 {
336 kvp.Value.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 515 kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
337 } 516 }
517
338 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) 518 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty)
339 { 519 {
340 if (!ResolveUserUuid(kvp.Value.CreatorID)) 520 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
341 kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 521 kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
342 } 522 }
523
343 if (UserManager != null) 524 if (UserManager != null)
344 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); 525 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
526
527 if (!ResolveGroupUuid(kvp.Value.GroupID))
528 kvp.Value.GroupID = UUID.Zero;
345 } 529 }
346 part.TaskInventory.LockItemsForRead(false); 530 part.TaskInventory.LockItemsForRead(false);
347 } 531 }
348 } 532 }
349 533
350 if (m_scene.AddRestoredSceneObject(sceneObject, true, false)) 534 if (scene.AddRestoredSceneObject(sceneObject, true, false))
351 { 535 {
352 sceneObjectsLoadedCount++; 536 sceneObjectsLoadedCount++;
353 sceneObject.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0); 537 sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0);
354 sceneObject.ResumeScripts(); 538 sceneObject.ResumeScripts();
355 } 539 }
356 } 540 }
@@ -365,16 +549,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
365 if (oldTelehubUUID != UUID.Zero) 549 if (oldTelehubUUID != UUID.Zero)
366 { 550 {
367 m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); 551 m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID);
368 m_scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; 552 scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero;
369 m_scene.RegionInfo.RegionSettings.ClearSpawnPoints(); 553 scene.RegionInfo.RegionSettings.ClearSpawnPoints();
370 } 554 }
371 } 555 }
372 556
373 /// <summary> 557 /// <summary>
374 /// Load serialized parcels. 558 /// Load serialized parcels.
375 /// </summary> 559 /// </summary>
560 /// <param name="scene"></param>
376 /// <param name="serialisedParcels"></param> 561 /// <param name="serialisedParcels"></param>
377 protected void LoadParcels(List<string> serialisedParcels) 562 protected void LoadParcels(Scene scene, List<string> serialisedParcels)
378 { 563 {
379 // Reload serialized parcels 564 // Reload serialized parcels
380 m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); 565 m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count);
@@ -382,9 +567,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
382 foreach (string serialisedParcel in serialisedParcels) 567 foreach (string serialisedParcel in serialisedParcels)
383 { 568 {
384 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); 569 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel);
385 if (!ResolveUserUuid(parcel.OwnerID))
386 parcel.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
387 570
571 // Validate User and Group UUID's
572
573 if (!ResolveUserUuid(scene, parcel.OwnerID))
574 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
575
576 if (!ResolveGroupUuid(parcel.GroupID))
577 {
578 parcel.GroupID = UUID.Zero;
579 parcel.IsGroupOwned = false;
580 }
581
582 List<LandAccessEntry> accessList = new List<LandAccessEntry>();
583 foreach (LandAccessEntry entry in parcel.ParcelAccessList)
584 {
585 if (ResolveUserUuid(scene, entry.AgentID))
586 accessList.Add(entry);
587 // else, drop this access rule
588 }
589 parcel.ParcelAccessList = accessList;
590
388// m_log.DebugFormat( 591// m_log.DebugFormat(
389// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}", 592// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}",
390// parcel.Name, parcel.LocalID, parcel.Area); 593// parcel.Name, parcel.LocalID, parcel.Area);
@@ -395,23 +598,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver
395 if (!m_merge) 598 if (!m_merge)
396 { 599 {
397 bool setupDefaultParcel = (landData.Count == 0); 600 bool setupDefaultParcel = (landData.Count == 0);
398 m_scene.LandChannel.Clear(setupDefaultParcel); 601 scene.LandChannel.Clear(setupDefaultParcel);
399 } 602 }
400 603
401 m_scene.EventManager.TriggerIncomingLandDataFromStorage(landData); 604 scene.EventManager.TriggerIncomingLandDataFromStorage(landData);
402 m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); 605 m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count);
403 } 606 }
404 607
405 /// <summary> 608 /// <summary>
406 /// Look up the given user id to check whether it's one that is valid for this grid. 609 /// Look up the given user id to check whether it's one that is valid for this grid.
407 /// </summary> 610 /// </summary>
611 /// <param name="scene"></param>
408 /// <param name="uuid"></param> 612 /// <param name="uuid"></param>
409 /// <returns></returns> 613 /// <returns></returns>
410 private bool ResolveUserUuid(UUID uuid) 614 private bool ResolveUserUuid(Scene scene, UUID uuid)
411 { 615 {
412 if (!m_validUserUuids.ContainsKey(uuid)) 616 if (!m_validUserUuids.ContainsKey(uuid))
413 { 617 {
414 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); 618 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
415 m_validUserUuids.Add(uuid, account != null); 619 m_validUserUuids.Add(uuid, account != null);
416 } 620 }
417 621
@@ -419,6 +623,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
419 } 623 }
420 624
421 /// <summary> 625 /// <summary>
626 /// Look up the given group id to check whether it's one that is valid for this grid.
627 /// </summary>
628 /// <param name="uuid"></param>
629 /// <returns></returns>
630 private bool ResolveGroupUuid(UUID uuid)
631 {
632 if (uuid == UUID.Zero)
633 return true; // this means the object has no group
634
635 if (!m_validGroupUuids.ContainsKey(uuid))
636 {
637 bool exists;
638
639 if (m_groupsModule == null)
640 exists = false;
641 else
642 exists = (m_groupsModule.GetGroupRecord(uuid) != null);
643
644 m_validGroupUuids.Add(uuid, exists);
645 }
646
647 return m_validGroupUuids[uuid];
648 }
649
422 /// Load an asset 650 /// Load an asset
423 /// </summary> 651 /// </summary>
424 /// <param name="assetFilename"></param> 652 /// <param name="assetFilename"></param>
@@ -442,7 +670,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
442 string extension = filename.Substring(i); 670 string extension = filename.Substring(i);
443 string uuid = filename.Remove(filename.Length - extension.Length); 671 string uuid = filename.Remove(filename.Length - extension.Length);
444 672
445 if (m_scene.AssetService.GetMetadata(uuid) != null) 673 if (m_assetService.GetMetadata(uuid) != null)
446 { 674 {
447 // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); 675 // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid);
448 return true; 676 return true;
@@ -462,7 +690,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
462 690
463 // We're relying on the asset service to do the sensible thing and not store the asset if it already 691 // We're relying on the asset service to do the sensible thing and not store the asset if it already
464 // exists. 692 // exists.
465 m_scene.AssetService.Store(asset); 693 m_assetService.Store(asset);
466 694
467 /** 695 /**
468 * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so 696 * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so
@@ -490,12 +718,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
490 /// <summary> 718 /// <summary>
491 /// Load region settings data 719 /// Load region settings data
492 /// </summary> 720 /// </summary>
721 /// <param name="scene"></param>
493 /// <param name="settingsPath"></param> 722 /// <param name="settingsPath"></param>
494 /// <param name="data"></param> 723 /// <param name="data"></param>
724 /// <param name="dearchivedScenes"></param>
495 /// <returns> 725 /// <returns>
496 /// true if settings were loaded successfully, false otherwise 726 /// true if settings were loaded successfully, false otherwise
497 /// </returns> 727 /// </returns>
498 private bool LoadRegionSettings(string settingsPath, byte[] data) 728 private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes)
499 { 729 {
500 RegionSettings loadedRegionSettings; 730 RegionSettings loadedRegionSettings;
501 731
@@ -511,7 +741,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
511 return false; 741 return false;
512 } 742 }
513 743
514 RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; 744 RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings;
515 745
516 currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; 746 currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit;
517 currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; 747 currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage;
@@ -548,12 +778,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
548 foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) 778 foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints())
549 currentRegionSettings.AddSpawnPoint(sp); 779 currentRegionSettings.AddSpawnPoint(sp);
550 780
781 currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime;
782 currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString();
783
551 currentRegionSettings.Save(); 784 currentRegionSettings.Save();
552 785
553 m_scene.TriggerEstateSunUpdate(); 786 scene.TriggerEstateSunUpdate();
554 787
555 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); 788 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
556
557 if (estateModule != null) 789 if (estateModule != null)
558 estateModule.sendRegionHandshakeToAll(); 790 estateModule.sendRegionHandshakeToAll();
559 791
@@ -563,14 +795,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
563 /// <summary> 795 /// <summary>
564 /// Load terrain data 796 /// Load terrain data
565 /// </summary> 797 /// </summary>
798 /// <param name="scene"></param>
566 /// <param name="terrainPath"></param> 799 /// <param name="terrainPath"></param>
567 /// <param name="data"></param> 800 /// <param name="data"></param>
568 /// <returns> 801 /// <returns>
569 /// true if terrain was resolved successfully, false otherwise. 802 /// true if terrain was resolved successfully, false otherwise.
570 /// </returns> 803 /// </returns>
571 private bool LoadTerrain(string terrainPath, byte[] data) 804 private bool LoadTerrain(Scene scene, string terrainPath, byte[] data)
572 { 805 {
573 ITerrainModule terrainModule = m_scene.RequestModuleInterface<ITerrainModule>(); 806 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
574 807
575 MemoryStream ms = new MemoryStream(data); 808 MemoryStream ms = new MemoryStream(data);
576 terrainModule.LoadFromStream(terrainPath, ms); 809 terrainModule.LoadFromStream(terrainPath, ms);
@@ -586,17 +819,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
586 /// </summary> 819 /// </summary>
587 /// <param name="path"></param> 820 /// <param name="path"></param>
588 /// <param name="data"></param> 821 /// <param name="data"></param>
589 public void LoadControlFile(string path, byte[] data) 822 /// <param name="dearchivedScenes"></param>
823 public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes)
590 { 824 {
591 XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); 825 XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
592 XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); 826 XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
593 XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); 827 XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context);
594 828
595 RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; 829 // Loaded metadata will be empty if no information exists in the archive
830 dearchivedScenes.LoadedCreationDateTime = 0;
831 dearchivedScenes.DefaultOriginalID = "";
596 832
597 // Loaded metadata will empty if no information exists in the archive 833 bool multiRegion = false;
598 currentRegionSettings.LoadedCreationDateTime = 0;
599 currentRegionSettings.LoadedCreationID = "";
600 834
601 while (xtr.Read()) 835 while (xtr.Read())
602 { 836 {
@@ -622,18 +856,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver
622 { 856 {
623 int value; 857 int value;
624 if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) 858 if (Int32.TryParse(xtr.ReadElementContentAsString(), out value))
625 currentRegionSettings.LoadedCreationDateTime = value; 859 dearchivedScenes.LoadedCreationDateTime = value;
626 } 860 }
627 else if (xtr.Name.ToString() == "id") 861 else if (xtr.Name.ToString() == "row")
862 {
863 multiRegion = true;
864 dearchivedScenes.StartRow();
865 }
866 else if (xtr.Name.ToString() == "region")
867 {
868 dearchivedScenes.StartRegion();
869 }
870 else if (xtr.Name.ToString() == "id")
871 {
872 string id = xtr.ReadElementContentAsString();
873 dearchivedScenes.DefaultOriginalID = id;
874 if (multiRegion)
875 dearchivedScenes.SetRegionOriginalID(id);
876 }
877 else if (xtr.Name.ToString() == "dir")
628 { 878 {
629 currentRegionSettings.LoadedCreationID = xtr.ReadElementContentAsString(); 879 dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString());
630 } 880 }
631 } 881 }
632 } 882 }
633 883
634 currentRegionSettings.Save(); 884 dearchivedScenes.MultiRegionFormat = multiRegion;
635 885 if (!multiRegion)
886 {
887 // Add the single scene
888 dearchivedScenes.StartRow();
889 dearchivedScenes.StartRegion();
890 dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID);
891 dearchivedScenes.SetRegionDirectory("");
892 }
893
636 ControlFileLoaded = true; 894 ControlFileLoaded = true;
895
896 return dearchivedScenes;
637 } 897 }
638 } 898 }
639} \ No newline at end of file 899}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
new file mode 100644
index 0000000..a66ed88
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
@@ -0,0 +1,176 @@
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.Linq;
31using System.Text;
32using OpenSim.Region.Framework.Scenes;
33using OpenMetaverse;
34using System.Drawing;
35
36namespace OpenSim.Region.CoreModules.World.Archiver
37{
38 /// <summary>
39 /// A group of regions arranged in a rectangle, possibly with holes.
40 /// </summary>
41 /// <remarks>
42 /// The regions usually (but not necessarily) belong to an archive file, in which case we
43 /// store additional information used to create the archive (e.g., each region's
44 /// directory within the archive).
45 /// </remarks>
46 public class ArchiveScenesGroup
47 {
48 /// <summary>
49 /// All the regions. The outer dictionary contains rows (key: Y coordinate).
50 /// The inner dictionaries contain each row's regions (key: X coordinate).
51 /// </summary>
52 public SortedDictionary<uint, SortedDictionary<uint, Scene>> Regions { get; set; }
53
54 /// <summary>
55 /// The subdirectory where each region is stored in the archive.
56 /// </summary>
57 protected Dictionary<UUID, string> m_regionDirs;
58
59 /// <summary>
60 /// The grid coordinates of the regions' bounding box.
61 /// </summary>
62 public Rectangle Rect { get; set; }
63
64
65 public ArchiveScenesGroup()
66 {
67 Regions = new SortedDictionary<uint, SortedDictionary<uint, Scene>>();
68 m_regionDirs = new Dictionary<UUID, string>();
69 Rect = new Rectangle(0, 0, 0, 0);
70 }
71
72 public void AddScene(Scene scene)
73 {
74 uint x = scene.RegionInfo.RegionLocX;
75 uint y = scene.RegionInfo.RegionLocY;
76
77 SortedDictionary<uint, Scene> row;
78 if (!Regions.TryGetValue(y, out row))
79 {
80 row = new SortedDictionary<uint, Scene>();
81 Regions[y] = row;
82 }
83
84 row[x] = scene;
85 }
86
87 /// <summary>
88 /// Called after all the scenes have been added. Performs calculations that require
89 /// knowledge of all the scenes.
90 /// </summary>
91 public void CalcSceneLocations()
92 {
93 if (Regions.Count == 0)
94 return;
95
96 // Find the bounding rectangle
97
98 uint firstY = Regions.First().Key;
99 uint lastY = Regions.Last().Key;
100
101 uint? firstX = null;
102 uint? lastX = null;
103
104 foreach (SortedDictionary<uint, Scene> row in Regions.Values)
105 {
106 uint curFirstX = row.First().Key;
107 uint curLastX = row.Last().Key;
108
109 firstX = (firstX == null) ? curFirstX : (firstX < curFirstX) ? firstX : curFirstX;
110 lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX;
111 }
112
113 Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastY - firstY + 1), (int)(lastX - firstX + 1));
114
115
116 // Calculate the subdirectory in which each region will be stored in the archive
117
118 m_regionDirs.Clear();
119 ForEachScene(delegate(Scene scene)
120 {
121 // We add the region's coordinates to ensure uniqueness even if multiple regions have the same name
122 string path = string.Format("{0}_{1}_{2}",
123 scene.RegionInfo.RegionLocX - Rect.X + 1,
124 scene.RegionInfo.RegionLocY - Rect.Y + 1,
125 scene.RegionInfo.RegionName.Replace(' ', '_'));
126 m_regionDirs[scene.RegionInfo.RegionID] = path;
127 });
128 }
129
130 /// <summary>
131 /// Returns the subdirectory where the region is stored.
132 /// </summary>
133 /// <param name="regionID"></param>
134 /// <returns></returns>
135 public string GetRegionDir(UUID regionID)
136 {
137 return m_regionDirs[regionID];
138 }
139
140 /// <summary>
141 /// Performs an action on all the scenes in this order: rows from South to North,
142 /// and within each row West to East.
143 /// </summary>
144 /// <param name="action"></param>
145 public void ForEachScene(Action<Scene> action)
146 {
147 foreach (SortedDictionary<uint, Scene> row in Regions.Values)
148 {
149 foreach (Scene scene in row.Values)
150 {
151 action(scene);
152 }
153 }
154 }
155
156 /// <summary>
157 /// Returns the scene at position 'location'.
158 /// </summary>
159 /// <param name="location">A location in the grid</param>
160 /// <param name="scene">The scene at this location</param>
161 /// <returns>Whether the scene was found</returns>
162 public bool TryGetScene(Point location, out Scene scene)
163 {
164 SortedDictionary<uint, Scene> row;
165 if (Regions.TryGetValue((uint)location.Y, out row))
166 {
167 if (row.TryGetValue((uint)location.X, out scene))
168 return true;
169 }
170
171 scene = null;
172 return false;
173 }
174
175 }
176}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
new file mode 100644
index 0000000..d751b1c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -0,0 +1,634 @@
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.IO;
31using System.IO.Compression;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using System.Xml;
36using log4net;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Serialization;
40using OpenSim.Region.CoreModules.World.Terrain;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode;
46using OpenSim.Framework.Serialization.External;
47
48namespace OpenSim.Region.CoreModules.World.Archiver
49{
50 /// <summary>
51 /// Prepare to write out an archive.
52 /// </summary>
53 public class ArchiveWriteRequest
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 /// <summary>
58 /// The minimum major version of OAR that we can write.
59 /// </summary>
60 public static int MIN_MAJOR_VERSION = 0;
61
62 /// <summary>
63 /// The maximum major version of OAR that we can write.
64 /// </summary>
65 public static int MAX_MAJOR_VERSION = 1;
66
67 /// <summary>
68 /// Whether we're saving a multi-region archive.
69 /// </summary>
70 public bool MultiRegionFormat { get; set; }
71
72 /// <summary>
73 /// Determine whether this archive will save assets. Default is true.
74 /// </summary>
75 public bool SaveAssets { get; set; }
76
77 /// <summary>
78 /// Determines which objects will be included in the archive, according to their permissions.
79 /// Default is null, meaning no permission checks.
80 /// </summary>
81 public string CheckPermissions { get; set; }
82
83 protected Scene m_rootScene;
84 protected Stream m_saveStream;
85 protected TarArchiveWriter m_archiveWriter;
86 protected Guid m_requestId;
87 protected Dictionary<string, object> m_options;
88
89 /// <summary>
90 /// Constructor
91 /// </summary>
92 /// <param name="module">Calling module</param>
93 /// <param name="savePath">The path to which to save data.</param>
94 /// <param name="requestId">The id associated with this request</param>
95 /// <exception cref="System.IO.IOException">
96 /// If there was a problem opening a stream for the file specified by the savePath
97 /// </exception>
98 public ArchiveWriteRequest(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
99 {
100 try
101 {
102 m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
103 }
104 catch (EntryPointNotFoundException e)
105 {
106 m_log.ErrorFormat(
107 "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
108 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
109 m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
110 }
111 }
112
113 /// <summary>
114 /// Constructor.
115 /// </summary>
116 /// <param name="scene">The root scene to archive</param>
117 /// <param name="saveStream">The stream to which to save data.</param>
118 /// <param name="requestId">The id associated with this request</param>
119 public ArchiveWriteRequest(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
120 {
121 m_saveStream = saveStream;
122 }
123
124 protected ArchiveWriteRequest(Scene scene, Guid requestId)
125 {
126 m_rootScene = scene;
127 m_requestId = requestId;
128 m_archiveWriter = null;
129
130 MultiRegionFormat = false;
131 SaveAssets = true;
132 CheckPermissions = null;
133 }
134
135 /// <summary>
136 /// Archive the region requested.
137 /// </summary>
138 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
139 public void ArchiveRegion(Dictionary<string, object> options)
140 {
141 m_options = options;
142
143 if (options.ContainsKey("all") && (bool)options["all"])
144 MultiRegionFormat = true;
145
146 if (options.ContainsKey("noassets") && (bool)options["noassets"])
147 SaveAssets = false;
148
149 Object temp;
150 if (options.TryGetValue("checkPermissions", out temp))
151 CheckPermissions = (string)temp;
152
153
154 // Find the regions to archive
155 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
156 if (MultiRegionFormat)
157 {
158 m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count);
159 SceneManager.Instance.ForEachScene(delegate(Scene scene)
160 {
161 scenesGroup.AddScene(scene);
162 });
163 }
164 else
165 {
166 scenesGroup.AddScene(m_rootScene);
167 }
168 scenesGroup.CalcSceneLocations();
169
170
171 m_archiveWriter = new TarArchiveWriter(m_saveStream);
172
173 try
174 {
175 // Write out control file. It should be first so that it will be found ASAP when loading the file.
176 m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup));
177 m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
178
179 // Archive the regions
180
181 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
182
183 scenesGroup.ForEachScene(delegate(Scene scene)
184 {
185 string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : "";
186 ArchiveOneRegion(scene, regionDir, assetUuids);
187 });
188
189 // Archive the assets
190
191 if (SaveAssets)
192 {
193 m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count);
194
195 // Asynchronously request all the assets required to perform this archive operation
196 AssetsRequest ar
197 = new AssetsRequest(
198 new AssetsArchiver(m_archiveWriter), assetUuids,
199 m_rootScene.AssetService, m_rootScene.UserAccountService,
200 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
201
202 Util.FireAndForget(o => ar.Execute());
203
204 // CloseArchive() will be called from ReceivedAllAssets()
205 }
206 else
207 {
208 m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
209 CloseArchive(string.Empty);
210 }
211 }
212 catch (Exception e)
213 {
214 CloseArchive(e.Message);
215 throw;
216 }
217 }
218
219
220 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
221 {
222 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
223
224 EntityBase[] entities = scene.GetEntities();
225 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
226
227 int numObjectsSkippedPermissions = 0;
228
229 // Filter entities so that we only have scene objects.
230 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
231 // end up having to do this
232 IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>();
233 foreach (EntityBase entity in entities)
234 {
235 if (entity is SceneObjectGroup)
236 {
237 SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
238
239 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
240 {
241 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule))
242 {
243 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
244 ++numObjectsSkippedPermissions;
245 }
246 else
247 {
248 sceneObjects.Add(sceneObject);
249 }
250 }
251 }
252 }
253
254 if (SaveAssets)
255 {
256 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService);
257 int prevAssets = assetUuids.Count;
258
259 foreach (SceneObjectGroup sceneObject in sceneObjects)
260 {
261 assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
262 }
263
264 m_log.DebugFormat(
265 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
266 sceneObjects.Count, assetUuids.Count - prevAssets);
267 }
268
269 if (numObjectsSkippedPermissions > 0)
270 {
271 m_log.DebugFormat(
272 "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
273 numObjectsSkippedPermissions);
274 }
275
276 // Make sure that we also request terrain texture assets
277 RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
278
279 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
280 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
281
282 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
283 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
284
285 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
286 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
287
288 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
289 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
290
291 Save(scene, sceneObjects, regionDir);
292 }
293
294 /// <summary>
295 /// Checks whether the user has permission to export an object group to an OAR.
296 /// </summary>
297 /// <param name="user">The user</param>
298 /// <param name="objGroup">The object group</param>
299 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
300 /// <param name="permissionsModule">The scene's permissions module</param>
301 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
302 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule)
303 {
304 if (checkPermissions == null)
305 return true;
306
307 if (permissionsModule == null)
308 return true; // this shouldn't happen
309
310 // Check whether the user is permitted to export all of the parts in the SOG. If any
311 // part can't be exported then the entire SOG can't be exported.
312
313 bool permitted = true;
314 //int primNumber = 1;
315
316 foreach (SceneObjectPart obj in objGroup.Parts)
317 {
318 uint perm;
319 PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj);
320 switch (permissionClass)
321 {
322 case PermissionClass.Owner:
323 perm = obj.BaseMask;
324 break;
325 case PermissionClass.Group:
326 perm = obj.GroupMask | obj.EveryoneMask;
327 break;
328 case PermissionClass.Everyone:
329 default:
330 perm = obj.EveryoneMask;
331 break;
332 }
333
334 bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
335 bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
336
337 // Special case: if Everyone can copy the object then this implies it can also be
338 // Transferred.
339 // However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
340 // always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
341 // does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
342 if (permissionClass != PermissionClass.Owner)
343 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
344
345 bool partPermitted = true;
346 if (checkPermissions.Contains("C") && !canCopy)
347 partPermitted = false;
348 if (checkPermissions.Contains("T") && !canTransfer)
349 partPermitted = false;
350
351 // If the user is the Creator of the object then it can always be included in the OAR
352 bool creator = (obj.CreatorID.Guid == user.Guid);
353 if (creator)
354 partPermitted = true;
355
356 //string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
357 //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
358 // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
359 // permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
360
361 if (!partPermitted)
362 {
363 permitted = false;
364 break;
365 }
366
367 //++primNumber;
368 }
369
370 return permitted;
371 }
372
373 /// <summary>
374 /// Create the control file.
375 /// </summary>
376 /// <returns></returns>
377 public string CreateControlFile(ArchiveScenesGroup scenesGroup)
378 {
379 int majorVersion;
380 int minorVersion;
381
382 if (MultiRegionFormat)
383 {
384 majorVersion = MAX_MAJOR_VERSION;
385 minorVersion = 0;
386 }
387 else
388 {
389 // To support older versions of OpenSim, we continue to create single-region OARs
390 // using the old file format. In the future this format will be discontinued.
391 majorVersion = 0;
392 minorVersion = 8;
393 }
394//
395// if (m_options.ContainsKey("version"))
396// {
397// string[] parts = m_options["version"].ToString().Split('.');
398// if (parts.Length >= 1)
399// {
400// majorVersion = Int32.Parse(parts[0]);
401//
402// if (parts.Length >= 2)
403// minorVersion = Int32.Parse(parts[1]);
404// }
405// }
406//
407// if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
408// {
409// throw new Exception(
410// string.Format(
411// "OAR version number for save must be between {0} and {1}",
412// MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
413// }
414// else if (majorVersion == MAX_MAJOR_VERSION)
415// {
416// // Force 1.0
417// minorVersion = 0;
418// }
419// else if (majorVersion == MIN_MAJOR_VERSION)
420// {
421// // Force 0.4
422// minorVersion = 4;
423// }
424
425 m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
426 if (majorVersion == 1)
427 {
428 m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR");
429 }
430
431 String s;
432
433 using (StringWriter sw = new StringWriter())
434 {
435 using (XmlTextWriter xtw = new XmlTextWriter(sw))
436 {
437 xtw.Formatting = Formatting.Indented;
438 xtw.WriteStartDocument();
439 xtw.WriteStartElement("archive");
440 xtw.WriteAttributeString("major_version", majorVersion.ToString());
441 xtw.WriteAttributeString("minor_version", minorVersion.ToString());
442
443 xtw.WriteStartElement("creation_info");
444 DateTime now = DateTime.UtcNow;
445 TimeSpan t = now - new DateTime(1970, 1, 1);
446 xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
447 if (!MultiRegionFormat)
448 xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString());
449 xtw.WriteEndElement();
450
451 xtw.WriteElementString("assets_included", SaveAssets.ToString());
452
453 if (MultiRegionFormat)
454 {
455 WriteRegionsManifest(scenesGroup, xtw);
456 }
457 else
458 {
459 xtw.WriteStartElement("region_info");
460 WriteRegionInfo(m_rootScene, xtw);
461 xtw.WriteEndElement();
462 }
463
464 xtw.WriteEndElement();
465
466 xtw.Flush();
467 }
468
469 s = sw.ToString();
470 }
471
472 return s;
473 }
474
475 /// <summary>
476 /// Writes the list of regions included in a multi-region OAR.
477 /// </summary>
478 private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw)
479 {
480 xtw.WriteStartElement("regions");
481
482 // Write the regions in order: rows from South to North, then regions from West to East.
483 // The list of regions can have "holes"; we write empty elements in their position.
484
485 for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y)
486 {
487 SortedDictionary<uint, Scene> row;
488 if (scenesGroup.Regions.TryGetValue(y, out row))
489 {
490 xtw.WriteStartElement("row");
491
492 for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x)
493 {
494 Scene scene;
495 if (row.TryGetValue(x, out scene))
496 {
497 xtw.WriteStartElement("region");
498 xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString());
499 xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID));
500 WriteRegionInfo(scene, xtw);
501 xtw.WriteEndElement();
502 }
503 else
504 {
505 // Write a placeholder for a missing region
506 xtw.WriteElementString("region", "");
507 }
508 }
509
510 xtw.WriteEndElement();
511 }
512 else
513 {
514 // Write a placeholder for a missing row
515 xtw.WriteElementString("row", "");
516 }
517 }
518
519 xtw.WriteEndElement(); // "regions"
520 }
521
522 protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
523 {
524 bool isMegaregion;
525 Vector2 size;
526
527 IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>();
528
529 if (rcMod != null)
530 isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID);
531 else
532 isMegaregion = false;
533
534 if (isMegaregion)
535 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
536 else
537 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
538
539 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
540 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
541 }
542
543
544 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
545 {
546 if (regionDir != string.Empty)
547 regionDir = ArchiveConstants.REGIONS_PATH + regionDir + "/";
548
549 m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
550
551 // Write out region settings
552 string settingsPath = String.Format("{0}{1}{2}.xml",
553 regionDir, ArchiveConstants.SETTINGS_PATH, scene.RegionInfo.RegionName);
554 m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(scene.RegionInfo.RegionSettings));
555
556 m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
557
558 // Write out land data (aka parcel) settings
559 List<ILandObject> landObjects = scene.LandChannel.AllParcels();
560 foreach (ILandObject lo in landObjects)
561 {
562 LandData landData = lo.LandData;
563 string landDataPath = String.Format("{0}{1}{2}.xml",
564 regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
565 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
566 }
567
568 m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
569
570 // Write out terrain
571 string terrainPath = String.Format("{0}{1}{2}.r32",
572 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
573
574 MemoryStream ms = new MemoryStream();
575 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
576 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
577 ms.Close();
578
579 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
580
581 // Write out scene object metadata
582 IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>();
583 foreach (SceneObjectGroup sceneObject in sceneObjects)
584 {
585 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
586
587 string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options);
588 string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject));
589 m_archiveWriter.WriteFile(objectPath, serializedObject);
590 }
591 }
592
593 protected void ReceivedAllAssets(
594 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
595 {
596 foreach (UUID uuid in assetsNotFoundUuids)
597 {
598 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
599 }
600
601 // m_log.InfoFormat(
602 // "[ARCHIVER]: Received {0} of {1} assets requested",
603 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
604
605 CloseArchive(String.Empty);
606 }
607
608
609 /// <summary>
610 /// Closes the archive and notifies that we're done.
611 /// </summary>
612 /// <param name="errorMessage">The error that occurred, or empty for success</param>
613 protected void CloseArchive(string errorMessage)
614 {
615 try
616 {
617 if (m_archiveWriter != null)
618 m_archiveWriter.Close();
619 m_saveStream.Close();
620 }
621 catch (Exception e)
622 {
623 m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e);
624 if (errorMessage == string.Empty)
625 errorMessage = e.Message;
626 }
627
628 m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName);
629
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 }
632
633 }
634}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
deleted file mode 100644
index 0780d86..0000000
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
+++ /dev/null
@@ -1,153 +0,0 @@
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.IO;
31using System.Reflection;
32using System.Xml;
33using log4net;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Serialization;
37using OpenSim.Framework.Serialization.External;
38using OpenSim.Region.CoreModules.World.Terrain;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.World.Archiver
43{
44 /// <summary>
45 /// Method called when all the necessary assets for an archive request have been received.
46 /// </summary>
47 public delegate void AssetsRequestCallback(
48 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
49
50 /// <summary>
51 /// Execute the write of an archive once we have received all the necessary data
52 /// </summary>
53 public class ArchiveWriteRequestExecution
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 protected ITerrainModule m_terrainModule;
58 protected IRegionSerialiserModule m_serialiser;
59 protected List<SceneObjectGroup> m_sceneObjects;
60 protected Scene m_scene;
61 protected TarArchiveWriter m_archiveWriter;
62 protected Guid m_requestId;
63 protected Dictionary<string, object> m_options;
64
65 public ArchiveWriteRequestExecution(
66 List<SceneObjectGroup> sceneObjects,
67 ITerrainModule terrainModule,
68 IRegionSerialiserModule serialiser,
69 Scene scene,
70 TarArchiveWriter archiveWriter,
71 Guid requestId,
72 Dictionary<string, object> options)
73 {
74 m_sceneObjects = sceneObjects;
75 m_terrainModule = terrainModule;
76 m_serialiser = serialiser;
77 m_scene = scene;
78 m_archiveWriter = archiveWriter;
79 m_requestId = requestId;
80 m_options = options;
81 }
82
83 protected internal void ReceivedAllAssets(
84 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
85 {
86 try
87 {
88 Save(assetsFoundUuids, assetsNotFoundUuids);
89 }
90 finally
91 {
92 m_archiveWriter.Close();
93 }
94
95 m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_scene.RegionInfo.RegionName);
96
97 m_scene.EventManager.TriggerOarFileSaved(m_requestId, String.Empty);
98 }
99
100 protected internal void Save(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
101 {
102 foreach (UUID uuid in assetsNotFoundUuids)
103 {
104 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
105 }
106
107// m_log.InfoFormat(
108// "[ARCHIVER]: Received {0} of {1} assets requested",
109// assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
110
111 m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
112
113 // Write out region settings
114 string settingsPath
115 = String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName);
116 m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings));
117
118 m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
119
120 // Write out land data (aka parcel) settings
121 List<ILandObject>landObjects = m_scene.LandChannel.AllParcels();
122 foreach (ILandObject lo in landObjects)
123 {
124 LandData landData = lo.LandData;
125 string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH,
126 landData.GlobalID.ToString());
127 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
128 }
129
130 m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
131
132 // Write out terrain
133 string terrainPath
134 = String.Format("{0}{1}.r32", ArchiveConstants.TERRAINS_PATH, m_scene.RegionInfo.RegionName);
135
136 MemoryStream ms = new MemoryStream();
137 m_terrainModule.SaveToStream(terrainPath, ms);
138 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
139 ms.Close();
140
141 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
142
143 // Write out scene object metadata
144 foreach (SceneObjectGroup sceneObject in m_sceneObjects)
145 {
146 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
147
148 string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options);
149 m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject);
150 }
151 }
152 }
153} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
deleted file mode 100644
index 4edaaca..0000000
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
+++ /dev/null
@@ -1,438 +0,0 @@
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.IO;
31using System.IO.Compression;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using System.Xml;
36using log4net;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Serialization;
40using OpenSim.Region.CoreModules.World.Terrain;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode;
46
47namespace OpenSim.Region.CoreModules.World.Archiver
48{
49 /// <summary>
50 /// Prepare to write out an archive.
51 /// </summary>
52 public class ArchiveWriteRequestPreparation
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 /// <summary>
57 /// The minimum major version of OAR that we can write.
58 /// </summary>
59 public static int MIN_MAJOR_VERSION = 0;
60
61 /// <summary>
62 /// The maximum major version of OAR that we can write.
63 /// </summary>
64 public static int MAX_MAJOR_VERSION = 0;
65
66 /// <summary>
67 /// Determine whether this archive will save assets. Default is true.
68 /// </summary>
69 public bool SaveAssets { get; set; }
70
71 protected ArchiverModule m_module;
72 protected Scene m_scene;
73 protected Stream m_saveStream;
74 protected Guid m_requestId;
75
76 /// <summary>
77 /// Constructor
78 /// </summary>
79 /// <param name="module">Calling module</param>
80 /// <param name="savePath">The path to which to save data.</param>
81 /// <param name="requestId">The id associated with this request</param>
82 /// <exception cref="System.IO.IOException">
83 /// If there was a problem opening a stream for the file specified by the savePath
84 /// </exception>
85 public ArchiveWriteRequestPreparation(ArchiverModule module, string savePath, Guid requestId) : this(module, requestId)
86 {
87 try
88 {
89 m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
90 }
91 catch (EntryPointNotFoundException e)
92 {
93 m_log.ErrorFormat(
94 "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
95 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
96 m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
97 }
98 }
99
100 /// <summary>
101 /// Constructor.
102 /// </summary>
103 /// <param name="module">Calling module</param>
104 /// <param name="saveStream">The stream to which to save data.</param>
105 /// <param name="requestId">The id associated with this request</param>
106 public ArchiveWriteRequestPreparation(ArchiverModule module, Stream saveStream, Guid requestId) : this(module, requestId)
107 {
108 m_saveStream = saveStream;
109 }
110
111 protected ArchiveWriteRequestPreparation(ArchiverModule module, Guid requestId)
112 {
113 m_module = module;
114
115 // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix
116 // this.
117 if (m_module != null)
118 m_scene = m_module.Scene;
119
120 m_requestId = requestId;
121
122 SaveAssets = true;
123 }
124
125 /// <summary>
126 /// Archive the region requested.
127 /// </summary>
128 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
129 public void ArchiveRegion(Dictionary<string, object> options)
130 {
131 if (options.ContainsKey("noassets") && (bool)options["noassets"])
132 SaveAssets = false;
133
134 try
135 {
136 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
137
138 EntityBase[] entities = m_scene.GetEntities();
139 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
140
141 string checkPermissions = null;
142 int numObjectsSkippedPermissions = 0;
143 Object temp;
144 if (options.TryGetValue("checkPermissions", out temp))
145 checkPermissions = (string)temp;
146
147 // Filter entities so that we only have scene objects.
148 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
149 // end up having to do this
150 foreach (EntityBase entity in entities)
151 {
152 if (entity is SceneObjectGroup)
153 {
154 SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
155
156 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
157 {
158 if (!CanUserArchiveObject(m_scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, checkPermissions))
159 {
160 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
161 ++numObjectsSkippedPermissions;
162 }
163 else
164 {
165 sceneObjects.Add(sceneObject);
166 }
167 }
168 }
169 }
170
171 if (SaveAssets)
172 {
173 UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService);
174
175 foreach (SceneObjectGroup sceneObject in sceneObjects)
176 {
177 assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
178 }
179
180 m_log.DebugFormat(
181 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
182 sceneObjects.Count, assetUuids.Count);
183 }
184 else
185 {
186 m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
187 }
188
189 if (numObjectsSkippedPermissions > 0)
190 {
191 m_log.DebugFormat(
192 "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
193 numObjectsSkippedPermissions);
194 }
195
196 // Make sure that we also request terrain texture assets
197 RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings;
198
199 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
200 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
201
202 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
203 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
204
205 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
206 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
207
208 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
209 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
210
211 TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream);
212
213 // Asynchronously request all the assets required to perform this archive operation
214 ArchiveWriteRequestExecution awre
215 = new ArchiveWriteRequestExecution(
216 sceneObjects,
217 m_scene.RequestModuleInterface<ITerrainModule>(),
218 m_scene.RequestModuleInterface<IRegionSerialiserModule>(),
219 m_scene,
220 archiveWriter,
221 m_requestId,
222 options);
223
224 m_log.InfoFormat("[ARCHIVER]: Creating archive file. This may take some time.");
225
226 // Write out control file. This has to be done first so that subsequent loaders will see this file first
227 // XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this
228 archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options));
229 m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
230
231 if (SaveAssets)
232 {
233 AssetsRequest ar
234 = new AssetsRequest(
235 new AssetsArchiver(archiveWriter), assetUuids,
236 m_scene.AssetService, m_scene.UserAccountService,
237 m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets);
238
239 Util.FireAndForget(o => ar.Execute());
240 }
241 else
242 {
243 awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>());
244 }
245 }
246 catch (Exception)
247 {
248 m_saveStream.Close();
249 throw;
250 }
251 }
252
253 /// <summary>
254 /// Checks whether the user has permission to export an object group to an OAR.
255 /// </summary>
256 /// <param name="user">The user</param>
257 /// <param name="objGroup">The object group</param>
258 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
259 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
260 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions)
261 {
262 if (checkPermissions == null)
263 return true;
264
265 IPermissionsModule module = m_scene.RequestModuleInterface<IPermissionsModule>();
266 if (module == null)
267 return true; // this shouldn't happen
268
269 // Check whether the user is permitted to export all of the parts in the SOG. If any
270 // part can't be exported then the entire SOG can't be exported.
271
272 bool permitted = true;
273 //int primNumber = 1;
274
275 foreach (SceneObjectPart obj in objGroup.Parts)
276 {
277 uint perm;
278 PermissionClass permissionClass = module.GetPermissionClass(user, obj);
279 switch (permissionClass)
280 {
281 case PermissionClass.Owner:
282 perm = obj.BaseMask;
283 break;
284 case PermissionClass.Group:
285 perm = obj.GroupMask | obj.EveryoneMask;
286 break;
287 case PermissionClass.Everyone:
288 default:
289 perm = obj.EveryoneMask;
290 break;
291 }
292
293 bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
294 bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
295
296 // Special case: if Everyone can copy the object then this implies it can also be
297 // Transferred.
298 // However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
299 // always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
300 // does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
301 if (permissionClass != PermissionClass.Owner)
302 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
303
304 bool partPermitted = true;
305 if (checkPermissions.Contains("C") && !canCopy)
306 partPermitted = false;
307 if (checkPermissions.Contains("T") && !canTransfer)
308 partPermitted = false;
309
310 // If the user is the Creator of the object then it can always be included in the OAR
311 bool creator = (obj.CreatorID.Guid == user.Guid);
312 if (creator)
313 partPermitted = true;
314
315 //string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
316 //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
317 // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
318 // permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
319
320 if (!partPermitted)
321 {
322 permitted = false;
323 break;
324 }
325
326 //++primNumber;
327 }
328
329 return permitted;
330 }
331
332 /// <summary>
333 /// Create the control file for the most up to date archive
334 /// </summary>
335 /// <returns></returns>
336 public string CreateControlFile(Dictionary<string, object> options)
337 {
338 int majorVersion = MAX_MAJOR_VERSION, minorVersion = 8;
339//
340// if (options.ContainsKey("version"))
341// {
342// string[] parts = options["version"].ToString().Split('.');
343// if (parts.Length >= 1)
344// {
345// majorVersion = Int32.Parse(parts[0]);
346//
347// if (parts.Length >= 2)
348// minorVersion = Int32.Parse(parts[1]);
349// }
350// }
351//
352// if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
353// {
354// throw new Exception(
355// string.Format(
356// "OAR version number for save must be between {0} and {1}",
357// MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
358// }
359// else if (majorVersion == MAX_MAJOR_VERSION)
360// {
361// // Force 1.0
362// minorVersion = 0;
363// }
364// else if (majorVersion == MIN_MAJOR_VERSION)
365// {
366// // Force 0.4
367// minorVersion = 4;
368// }
369
370 m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
371 //if (majorVersion == 1)
372 //{
373 // m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR");
374 //}
375
376 String s;
377
378 using (StringWriter sw = new StringWriter())
379 {
380 using (XmlTextWriter xtw = new XmlTextWriter(sw))
381 {
382 xtw.Formatting = Formatting.Indented;
383 xtw.WriteStartDocument();
384 xtw.WriteStartElement("archive");
385 xtw.WriteAttributeString("major_version", majorVersion.ToString());
386 xtw.WriteAttributeString("minor_version", minorVersion.ToString());
387
388 xtw.WriteStartElement("creation_info");
389 DateTime now = DateTime.UtcNow;
390 TimeSpan t = now - new DateTime(1970, 1, 1);
391 xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
392 xtw.WriteElementString("id", UUID.Random().ToString());
393 xtw.WriteEndElement();
394
395 xtw.WriteStartElement("region_info");
396
397 bool isMegaregion;
398 Vector2 size;
399 IRegionCombinerModule rcMod = null;
400
401 // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix
402 // this, possibly by doing control file creation somewhere else.
403 if (m_module != null)
404 rcMod = m_module.RegionCombinerModule;
405
406 if (rcMod != null)
407 isMegaregion = rcMod.IsRootForMegaregion(m_scene.RegionInfo.RegionID);
408 else
409 isMegaregion = false;
410
411 if (isMegaregion)
412 size = rcMod.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
413 else
414 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
415
416 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
417 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
418
419 xtw.WriteEndElement();
420
421 xtw.WriteElementString("assets_included", SaveAssets.ToString());
422
423 xtw.WriteEndElement();
424
425 xtw.Flush();
426 }
427
428 s = sw.ToString();
429 }
430
431// if (m_scene != null)
432// Console.WriteLine(
433// "[ARCHIVE WRITE REQUEST PREPARATION]: Control file for {0} is: {1}", m_scene.RegionInfo.RegionName, s);
434
435 return s;
436 }
437 }
438}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index bf3b124..2a87dc2 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -146,6 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
146 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); 146 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
147 ops.Add("publish", v => options["wipe-owners"] = v != null); 147 ops.Add("publish", v => options["wipe-owners"] = v != null);
148 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; }); 148 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; });
149 ops.Add("all", delegate(string v) { options["all"] = v != null; });
149 150
150 List<string> mainParams = ops.Parse(cmdparams); 151 List<string> mainParams = ops.Parse(cmdparams);
151 152
@@ -169,7 +170,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
169 m_log.InfoFormat( 170 m_log.InfoFormat(
170 "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); 171 "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath);
171 172
172 new ArchiveWriteRequestPreparation(this, savePath, requestId).ArchiveRegion(options); 173 new ArchiveWriteRequest(Scene, savePath, requestId).ArchiveRegion(options);
173 } 174 }
174 175
175 public void ArchiveRegion(Stream saveStream) 176 public void ArchiveRegion(Stream saveStream)
@@ -184,7 +185,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
184 185
185 public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options) 186 public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options)
186 { 187 {
187 new ArchiveWriteRequestPreparation(this, saveStream, requestId).ArchiveRegion(options); 188 new ArchiveWriteRequest(Scene, saveStream, requestId).ArchiveRegion(options);
188 } 189 }
189 190
190 public void DearchiveRegion(string loadPath) 191 public void DearchiveRegion(string loadPath)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index 89e9593..bf58591 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -46,6 +46,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
46 { 46 {
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 /// <summary>
50 /// Method called when all the necessary assets for an archive request have been received.
51 /// </summary>
52 public delegate void AssetsRequestCallback(
53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
54
49 enum RequestState 55 enum RequestState
50 { 56 {
51 Initial, 57 Initial,
diff --git a/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs
new file mode 100644
index 0000000..3dcc020
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs
@@ -0,0 +1,232 @@
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.Linq;
31using System.Text;
32using OpenSim.Region.Framework.Scenes;
33using OpenMetaverse;
34using System.Drawing;
35using log4net;
36using System.Reflection;
37using OpenSim.Framework.Serialization;
38
39namespace OpenSim.Region.CoreModules.World.Archiver
40{
41 /// <summary>
42 /// The regions included in an OAR file.
43 /// </summary>
44 public class DearchiveScenesInfo
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 /// <summary>
49 /// One region in the archive.
50 /// </summary>
51 public class RegionInfo
52 {
53 /// <summary>
54 /// The subdirectory in which the region is stored.
55 /// </summary>
56 public string Directory { get; set; }
57
58 /// <summary>
59 /// The region's coordinates (relative to the South-West corner of the block).
60 /// </summary>
61 public Point Location { get; set; }
62
63 /// <summary>
64 /// The UUID of the original scene from which this archived region was saved.
65 /// </summary>
66 public string OriginalID { get; set; }
67
68 /// <summary>
69 /// The scene in the current simulator into which this region is loaded.
70 /// If null then the region doesn't have a corresponding scene, and it won't be loaded.
71 /// </summary>
72 public Scene Scene { get; set; }
73 }
74
75 /// <summary>
76 /// Whether this archive uses the multi-region format.
77 /// </summary>
78 public Boolean MultiRegionFormat { get; set; }
79
80 /// <summary>
81 /// Maps (Region directory -> region)
82 /// </summary>
83 protected Dictionary<string, RegionInfo> m_directory2region = new Dictionary<string, RegionInfo>();
84
85 /// <summary>
86 /// Maps (UUID of the scene in the simulator where the region will be loaded -> region)
87 /// </summary>
88 protected Dictionary<UUID, RegionInfo> m_newId2region = new Dictionary<UUID, RegionInfo>();
89
90 public int LoadedCreationDateTime { get; set; }
91 public string DefaultOriginalID { get; set; }
92
93 // These variables are used while reading the archive control file
94 protected int? m_curY = null;
95 protected int? m_curX = null;
96 protected RegionInfo m_curRegion;
97
98
99 public DearchiveScenesInfo()
100 {
101 MultiRegionFormat = false;
102 }
103
104
105 // The following methods are used while reading the archive control file
106
107 public void StartRow()
108 {
109 m_curY = (m_curY == null) ? 0 : m_curY + 1;
110 m_curX = null;
111 }
112
113 public void StartRegion()
114 {
115 m_curX = (m_curX == null) ? 0 : m_curX + 1;
116 // Note: this doesn't mean we have a real region in this location; this could just be a "hole"
117 }
118
119 public void SetRegionOriginalID(string id)
120 {
121 m_curRegion = new RegionInfo();
122 m_curRegion.Location = new Point((int)m_curX, (int)m_curY);
123 m_curRegion.OriginalID = id;
124 // 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called
125 }
126
127 public void SetRegionDirectory(string directory)
128 {
129 m_curRegion.Directory = directory;
130 m_directory2region[directory] = m_curRegion;
131 }
132
133
134 /// <summary>
135 /// Sets all the scenes present in the simulator.
136 /// </summary>
137 /// <remarks>
138 /// This method matches regions in the archive to scenes in the simulator according to
139 /// their relative position. We only load regions if there's an existing Scene in the
140 /// grid location where the region should be loaded.
141 /// </remarks>
142 /// <param name="rootScene">The scene where the Load OAR operation was run</param>
143 /// <param name="simulatorScenes">All the scenes in the simulator</param>
144 public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes)
145 {
146 foreach (RegionInfo archivedRegion in m_directory2region.Values)
147 {
148 Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY);
149 location.Offset(archivedRegion.Location);
150
151 Scene scene;
152 if (simulatorScenes.TryGetScene(location, out scene))
153 {
154 archivedRegion.Scene = scene;
155 m_newId2region[scene.RegionInfo.RegionID] = archivedRegion;
156 }
157 else
158 {
159 m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}",
160 archivedRegion.Directory, location.X, location.Y);
161 }
162 }
163 }
164
165 /// <summary>
166 /// Returns the archived region according to the path of a file in the archive.
167 /// Also, converts the full path into a path that is relative to the region's directory.
168 /// </summary>
169 /// <param name="fullPath">The path of a file in the archive</param>
170 /// <param name="scene">The corresponding Scene, or null if none</param>
171 /// <param name="relativePath">The path relative to the region's directory. (Or the original
172 /// path, if this file doesn't belong to a region.)</param>
173 /// <returns>True: use this file; False: skip it</returns>
174 public bool GetRegionFromPath(string fullPath, out Scene scene, out string relativePath)
175 {
176 scene = null;
177 relativePath = fullPath;
178
179 if (!MultiRegionFormat)
180 {
181 if (m_newId2region.Count > 0)
182 scene = m_newId2region.First().Value.Scene;
183 return true;
184 }
185
186 if (!fullPath.StartsWith(ArchiveConstants.REGIONS_PATH))
187 return true; // this file doesn't belong to a region
188
189 string[] parts = fullPath.Split(new Char[] { '/' }, 3);
190 if (parts.Length != 3)
191 return false;
192 string regionDirectory = parts[1];
193 relativePath = parts[2];
194
195 RegionInfo region;
196 if (m_directory2region.TryGetValue(regionDirectory, out region))
197 {
198 scene = region.Scene;
199 return (scene != null);
200 }
201 else
202 {
203 return false;
204 }
205 }
206
207 /// <summary>
208 /// Returns the original UUID of a region (from the simulator where the OAR was saved),
209 /// given the UUID of the scene it was loaded into in the current simulator.
210 /// </summary>
211 /// <param name="newID"></param>
212 /// <returns></returns>
213 public string GetOriginalRegionID(UUID newID)
214 {
215 RegionInfo region;
216 if (m_newId2region.TryGetValue(newID, out region))
217 return region.OriginalID;
218 else
219 return DefaultOriginalID;
220 }
221
222 /// <summary>
223 /// Returns the scenes that have been (or will be) loaded.
224 /// </summary>
225 /// <returns></returns>
226 public List<UUID> GetLoadedScenes()
227 {
228 return m_newId2region.Keys.ToList();
229 }
230
231 }
232}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index 5deaf52..82f49b0 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -47,32 +47,41 @@ using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
47using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; 47using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader;
48using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; 48using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter;
49using RegionSettings = OpenSim.Framework.RegionSettings; 49using RegionSettings = OpenSim.Framework.RegionSettings;
50using OpenSim.Region.Framework.Interfaces;
50 51
51namespace OpenSim.Region.CoreModules.World.Archiver.Tests 52namespace OpenSim.Region.CoreModules.World.Archiver.Tests
52{ 53{
53 [TestFixture] 54 [TestFixture]
54 public class ArchiverTests 55 public class ArchiverTests : OpenSimTestCase
55 { 56 {
56 private Guid m_lastRequestId; 57 private Guid m_lastRequestId;
57 private string m_lastErrorMessage; 58 private string m_lastErrorMessage;
58 59
60 protected SceneHelpers m_sceneHelpers;
59 protected TestScene m_scene; 61 protected TestScene m_scene;
60 protected ArchiverModule m_archiverModule; 62 protected ArchiverModule m_archiverModule;
63 protected SerialiserModule m_serialiserModule;
61 64
62 protected TaskInventoryItem m_soundItem; 65 protected TaskInventoryItem m_soundItem;
63 66
64 [SetUp] 67 [SetUp]
65 public void SetUp() 68 public override void SetUp()
66 { 69 {
70 base.SetUp();
71
72 // FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later
73 new SceneManager();
74
67 m_archiverModule = new ArchiverModule(); 75 m_archiverModule = new ArchiverModule();
68 SerialiserModule serialiserModule = new SerialiserModule(); 76 m_serialiserModule = new SerialiserModule();
69 TerrainModule terrainModule = new TerrainModule(); 77 TerrainModule terrainModule = new TerrainModule();
70 78
71 m_scene = new SceneHelpers().SetupScene(); 79 m_sceneHelpers = new SceneHelpers();
72 SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); 80 m_scene = m_sceneHelpers.SetupScene();
81 SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, m_serialiserModule, terrainModule);
73 } 82 }
74 83
75 private void LoadCompleted(Guid requestId, string errorMessage) 84 private void LoadCompleted(Guid requestId, List<UUID> loadedScenes, string errorMessage)
76 { 85 {
77 lock (this) 86 lock (this)
78 { 87 {
@@ -128,26 +137,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
128 TestHelpers.InMethod(); 137 TestHelpers.InMethod();
129// log4net.Config.XmlConfigurator.Configure(); 138// log4net.Config.XmlConfigurator.Configure();
130 139
131 SceneObjectPart part1 = CreateSceneObjectPart1(); 140 SceneObjectGroup sog1;
132 SceneObjectGroup sog1 = new SceneObjectGroup(part1); 141 SceneObjectGroup sog2;
133 m_scene.AddNewSceneObject(sog1, false); 142 UUID ncAssetUuid;
134 143 CreateTestObjects(m_scene, out sog1, out sog2, out ncAssetUuid);
135 SceneObjectPart part2 = CreateSceneObjectPart2();
136
137 AssetNotecard nc = new AssetNotecard();
138 nc.BodyText = "Hello World!";
139 nc.Encode();
140 UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000");
141 UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000");
142 AssetBase ncAsset
143 = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
144 m_scene.AssetService.Store(ncAsset);
145 SceneObjectGroup sog2 = new SceneObjectGroup(part2);
146 TaskInventoryItem ncItem
147 = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
148 part2.Inventory.AddInventoryItem(ncItem, true);
149
150 m_scene.AddNewSceneObject(sog2, false);
151 144
152 MemoryStream archiveWriteStream = new MemoryStream(); 145 MemoryStream archiveWriteStream = new MemoryStream();
153 m_scene.EventManager.OnOarFileSaved += SaveCompleted; 146 m_scene.EventManager.OnOarFileSaved += SaveCompleted;
@@ -186,7 +179,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
186 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 179 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
187 180
188 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 181 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
189 arr.LoadControlFile(filePath, data); 182 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
190 183
191 Assert.That(arr.ControlFileLoaded, Is.True); 184 Assert.That(arr.ControlFileLoaded, Is.True);
192 185
@@ -211,6 +204,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
211 // TODO: Test presence of more files and contents of files. 204 // TODO: Test presence of more files and contents of files.
212 } 205 }
213 206
207 private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
208 {
209 SceneObjectPart part1 = CreateSceneObjectPart1();
210 sog1 = new SceneObjectGroup(part1);
211 scene.AddNewSceneObject(sog1, false);
212
213 AssetNotecard nc = new AssetNotecard();
214 nc.BodyText = "Hello World!";
215 nc.Encode();
216 ncAssetUuid = UUID.Random();
217 UUID ncItemUuid = UUID.Random();
218 AssetBase ncAsset
219 = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
220 m_scene.AssetService.Store(ncAsset);
221
222 TaskInventoryItem ncItem
223 = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
224 SceneObjectPart part2 = CreateSceneObjectPart2();
225 sog2 = new SceneObjectGroup(part2);
226 part2.Inventory.AddInventoryItem(ncItem, true);
227
228 scene.AddNewSceneObject(sog2, false);
229 }
230
214 /// <summary> 231 /// <summary>
215 /// Test saving an OpenSim Region Archive with the no assets option 232 /// Test saving an OpenSim Region Archive with the no assets option
216 /// </summary> 233 /// </summary>
@@ -270,7 +287,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
270 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 287 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
271 288
272 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 289 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
273 arr.LoadControlFile(filePath, data); 290 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
274 291
275 Assert.That(arr.ControlFileLoaded, Is.True); 292 Assert.That(arr.ControlFileLoaded, Is.True);
276 293
@@ -307,7 +324,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
307 324
308 tar.WriteFile( 325 tar.WriteFile(
309 ArchiveConstants.CONTROL_FILE_PATH, 326 ArchiveConstants.CONTROL_FILE_PATH,
310 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 327 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
311 328
312 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); 329 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
313 SceneObjectPart sop2 330 SceneObjectPart sop2
@@ -362,11 +379,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
362 // Also check that direct entries which will also have a file entry containing that directory doesn't 379 // Also check that direct entries which will also have a file entry containing that directory doesn't
363 // upset load 380 // upset load
364 tar.WriteDir(ArchiveConstants.TERRAINS_PATH); 381 tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
365 382
366 tar.WriteFile( 383 tar.WriteFile(
367 ArchiveConstants.CONTROL_FILE_PATH, 384 ArchiveConstants.CONTROL_FILE_PATH,
368 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 385 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
369
370 SceneObjectPart part1 = CreateSceneObjectPart1(); 386 SceneObjectPart part1 = CreateSceneObjectPart1();
371 387
372 part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); 388 part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
@@ -389,31 +405,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
389 Assert.That(soundDataResourceName, Is.Not.Null); 405 Assert.That(soundDataResourceName, Is.Not.Null);
390 406
391 byte[] soundData; 407 byte[] soundData;
392 Console.WriteLine("Loading " + soundDataResourceName); 408 UUID soundUuid;
393 using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) 409 CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
394 { 410
395 using (BinaryReader br = new BinaryReader(resource)) 411 TaskInventoryItem item1
396 { 412 = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
397 // FIXME: Use the inspector instead 413 part1.Inventory.AddInventoryItem(item1, true);
398 soundData = br.ReadBytes(99999999);
399 UUID soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
400 string soundAssetFileName
401 = ArchiveConstants.ASSETS_PATH + soundUuid
402 + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
403 tar.WriteFile(soundAssetFileName, soundData);
404
405 /*
406 AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
407 scene.AssetService.Store(soundAsset);
408 asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
409 */
410
411 TaskInventoryItem item1
412 = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
413 part1.Inventory.AddInventoryItem(item1, true);
414 }
415 }
416
417 m_scene.AddNewSceneObject(object1, false); 414 m_scene.AddNewSceneObject(object1, false);
418 415
419 string object1FileName = string.Format( 416 string object1FileName = string.Format(
@@ -435,6 +432,34 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
435 432
436 Assert.That(m_lastErrorMessage, Is.Null); 433 Assert.That(m_lastErrorMessage, Is.Null);
437 434
435 TestLoadedRegion(part1, soundItemName, soundData);
436 }
437
438 private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
439 {
440 using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
441 {
442 using (BinaryReader br = new BinaryReader(resource))
443 {
444 // FIXME: Use the inspector instead
445 soundData = br.ReadBytes(99999999);
446 soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
447 string soundAssetFileName
448 = ArchiveConstants.ASSETS_PATH + soundUuid
449 + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
450 tar.WriteFile(soundAssetFileName, soundData);
451
452 /*
453 AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
454 scene.AssetService.Store(soundAsset);
455 asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
456 */
457 }
458 }
459 }
460
461 private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
462 {
438 SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); 463 SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
439 464
440 Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); 465 Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
@@ -454,9 +479,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
454 Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); 479 Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
455 480
456 Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); 481 Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
457
458 // Temporary
459 Console.WriteLine("Successfully completed {0}", MethodBase.GetCurrentMethod());
460 } 482 }
461 483
462 /// <summary> 484 /// <summary>
@@ -516,7 +538,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
516 SerialiserModule serialiserModule = new SerialiserModule(); 538 SerialiserModule serialiserModule = new SerialiserModule();
517 TerrainModule terrainModule = new TerrainModule(); 539 TerrainModule terrainModule = new TerrainModule();
518 540
519 TestScene scene2 = new SceneHelpers().SetupScene(); 541 m_sceneHelpers = new SceneHelpers();
542 TestScene scene2 = m_sceneHelpers.SetupScene();
520 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); 543 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
521 544
522 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is 545 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
@@ -554,7 +577,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
554 tar.WriteDir(ArchiveConstants.TERRAINS_PATH); 577 tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
555 tar.WriteFile( 578 tar.WriteFile(
556 ArchiveConstants.CONTROL_FILE_PATH, 579 ArchiveConstants.CONTROL_FILE_PATH,
557 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 580 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
558 581
559 RegionSettings rs = new RegionSettings(); 582 RegionSettings rs = new RegionSettings();
560 rs.AgentLimit = 17; 583 rs.AgentLimit = 17;
@@ -664,7 +687,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
664 SerialiserModule serialiserModule = new SerialiserModule(); 687 SerialiserModule serialiserModule = new SerialiserModule();
665 TerrainModule terrainModule = new TerrainModule(); 688 TerrainModule terrainModule = new TerrainModule();
666 689
667 Scene scene = new SceneHelpers().SetupScene(); 690 Scene scene = m_sceneHelpers.SetupScene();
668 SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule); 691 SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
669 692
670 m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); 693 m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false);
@@ -700,5 +723,258 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
700 Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2.GroupPosition), "object2 group position not equal after merge"); 723 Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2.GroupPosition), "object2 group position not equal after merge");
701 } 724 }
702 } 725 }
726
727 /// <summary>
728 /// Test saving a multi-region OAR.
729 /// </summary>
730 [Test]
731 public void TestSaveMultiRegionOar()
732 {
733 TestHelpers.InMethod();
734
735 // Create test regions
736
737 int WIDTH = 2;
738 int HEIGHT = 2;
739
740 List<Scene> scenes = new List<Scene>();
741
742 // Maps (Directory in OAR file -> scene)
743 Dictionary<string, Scene> regionPaths = new Dictionary<string, Scene>();
744
745 // Maps (Scene -> expected object paths)
746 Dictionary<UUID, List<string>> expectedPaths = new Dictionary<UUID, List<string>>();
747
748 // List of expected assets
749 List<UUID> expectedAssets = new List<UUID>();
750
751 for (uint y = 0; y < HEIGHT; y++)
752 {
753 for (uint x = 0; x < WIDTH; x++)
754 {
755 Scene scene;
756 if (x == 0 && y == 0)
757 {
758 scene = m_scene; // this scene was already created in SetUp()
759 }
760 else
761 {
762 scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
763 SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
764 }
765 scenes.Add(scene);
766
767 string dir = String.Format("{0}_{1}_{2}", x + 1, y + 1, scene.RegionInfo.RegionName.Replace(" ", "_"));
768 regionPaths[dir] = scene;
769
770 SceneObjectGroup sog1;
771 SceneObjectGroup sog2;
772 UUID ncAssetUuid;
773
774 CreateTestObjects(scene, out sog1, out sog2, out ncAssetUuid);
775
776 expectedPaths[scene.RegionInfo.RegionID] = new List<string>();
777 expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog1));
778 expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog2));
779
780 expectedAssets.Add(ncAssetUuid);
781 }
782 }
783
784
785 // Save OAR
786
787 MemoryStream archiveWriteStream = new MemoryStream();
788 m_scene.EventManager.OnOarFileSaved += SaveCompleted;
789
790 Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
791
792 Dictionary<string, Object> options = new Dictionary<string, Object>();
793 options.Add("all", true);
794
795 lock (this)
796 {
797 m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options);
798 Monitor.Wait(this, 60000);
799 }
800
801
802 // Check that the OAR contains the expected data
803
804 Assert.That(m_lastRequestId, Is.EqualTo(requestId));
805
806 byte[] archive = archiveWriteStream.ToArray();
807 MemoryStream archiveReadStream = new MemoryStream(archive);
808 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
809
810 Dictionary<UUID, List<string>> foundPaths = new Dictionary<UUID, List<string>>();
811 List<UUID> foundAssets = new List<UUID>();
812
813 foreach (Scene scene in scenes)
814 {
815 foundPaths[scene.RegionInfo.RegionID] = new List<string>();
816 }
817
818 string filePath;
819 TarArchiveReader.TarEntryType tarEntryType;
820
821 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
822 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
823
824 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
825 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
826
827 Assert.That(arr.ControlFileLoaded, Is.True);
828
829 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
830 {
831 if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
832 {
833 // Assets are shared, so this file doesn't belong to any specific region.
834 string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
835 if (fileName.EndsWith("_notecard.txt"))
836 foundAssets.Add(UUID.Parse(fileName.Substring(0, fileName.Length - "_notecard.txt".Length)));
837 }
838 else
839 {
840 // This file belongs to one of the regions. Find out which one.
841 Assert.IsTrue(filePath.StartsWith(ArchiveConstants.REGIONS_PATH));
842 string[] parts = filePath.Split(new Char[] { '/' }, 3);
843 Assert.AreEqual(3, parts.Length);
844 string regionDirectory = parts[1];
845 string relativePath = parts[2];
846 Scene scene = regionPaths[regionDirectory];
847
848 if (relativePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
849 {
850 foundPaths[scene.RegionInfo.RegionID].Add(relativePath);
851 }
852 }
853 }
854
855 Assert.AreEqual(scenes.Count, foundPaths.Count);
856 foreach (Scene scene in scenes)
857 {
858 Assert.That(foundPaths[scene.RegionInfo.RegionID], Is.EquivalentTo(expectedPaths[scene.RegionInfo.RegionID]));
859 }
860
861 Assert.That(foundAssets, Is.EquivalentTo(expectedAssets));
862 }
863
864 /// <summary>
865 /// Test loading a multi-region OAR.
866 /// </summary>
867 [Test]
868 public void TestLoadMultiRegionOar()
869 {
870 TestHelpers.InMethod();
871
872 // Create an ArchiveScenesGroup with the regions in the OAR. This is needed to generate the control file.
873
874 int WIDTH = 2;
875 int HEIGHT = 2;
876
877 for (uint y = 0; y < HEIGHT; y++)
878 {
879 for (uint x = 0; x < WIDTH; x++)
880 {
881 Scene scene;
882 if (x == 0 && y == 0)
883 {
884 scene = m_scene; // this scene was already created in SetUp()
885 }
886 else
887 {
888 scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
889 SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
890 }
891 }
892 }
893
894 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
895 SceneManager.Instance.ForEachScene(delegate(Scene scene)
896 {
897 scenesGroup.AddScene(scene);
898 });
899 scenesGroup.CalcSceneLocations();
900
901 // Generate the OAR file
902
903 MemoryStream archiveWriteStream = new MemoryStream();
904 TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
905
906 ArchiveWriteRequest writeRequest = new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty);
907 writeRequest.MultiRegionFormat = true;
908 tar.WriteFile(
909 ArchiveConstants.CONTROL_FILE_PATH, writeRequest.CreateControlFile(scenesGroup));
910
911 SceneObjectPart part1 = CreateSceneObjectPart1();
912 part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
913 part1.SitTargetPosition = new Vector3(1, 2, 3);
914
915 SceneObjectGroup object1 = new SceneObjectGroup(part1);
916
917 // Let's put some inventory items into our object
918 string soundItemName = "sound-item1";
919 UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
920 Type type = GetType();
921 Assembly assembly = type.Assembly;
922 string soundDataResourceName = null;
923 string[] names = assembly.GetManifestResourceNames();
924 foreach (string name in names)
925 {
926 if (name.EndsWith(".Resources.test-sound.wav"))
927 soundDataResourceName = name;
928 }
929 Assert.That(soundDataResourceName, Is.Not.Null);
930
931 byte[] soundData;
932 UUID soundUuid;
933 CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
934
935 TaskInventoryItem item1
936 = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
937 part1.Inventory.AddInventoryItem(item1, true);
938 m_scene.AddNewSceneObject(object1, false);
939
940 string object1FileName = string.Format(
941 "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
942 part1.Name,
943 Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z),
944 part1.UUID);
945 string path = "regions/1_1_Unit_test_region/" + ArchiveConstants.OBJECTS_PATH + object1FileName;
946 tar.WriteFile(path, SceneObjectSerializer.ToXml2Format(object1));
947
948 tar.Close();
949
950
951 // Delete the current objects, to test that they're loaded from the OAR and didn't
952 // just remain in the scene.
953 SceneManager.Instance.ForEachScene(delegate(Scene scene)
954 {
955 scene.DeleteAllSceneObjects();
956 });
957
958 // Create a "hole", to test that that the corresponding region isn't loaded from the OAR
959 SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]);
960
961
962 // Check thay the OAR file contains the expected data
963
964 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
965
966 lock (this)
967 {
968 m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
969 m_archiverModule.DearchiveRegion(archiveReadStream);
970 }
971
972 Assert.That(m_lastErrorMessage, Is.Null);
973
974 Assert.AreEqual(3, SceneManager.Instance.Scenes.Count);
975
976 TestLoadedRegion(part1, soundItemName, soundData);
977 }
978
703 } 979 }
704} 980}
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index fdef9d8..5fd1bce 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -40,6 +40,7 @@ using OpenMetaverse;
40using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using RegionFlags = OpenMetaverse.RegionFlags;
43 44
44namespace OpenSim.Region.CoreModules.World.Estate 45namespace OpenSim.Region.CoreModules.World.Estate
45{ 46{
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 4f06737..d5b2adb 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -33,6 +33,7 @@ using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using RegionFlags = OpenMetaverse.RegionFlags;
36 37
37namespace OpenSim.Region.CoreModules.World.Land 38namespace OpenSim.Region.CoreModules.World.Land
38{ 39{
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index 102b4d7..cbb3abe 100644
--- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
@@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.World.Land
69 /// without recounting the whole sim. 69 /// without recounting the whole sim.
70 /// 70 ///
71 /// We start out tainted so that the first get call resets the various prim counts. 71 /// We start out tainted so that the first get call resets the various prim counts.
72 /// <value> 72 /// </value>
73 private bool m_Tainted = true; 73 private bool m_Tainted = true;
74 74
75 private Object m_TaintLock = new Object(); 75 private Object m_TaintLock = new Object();
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index 09f6758..7a35182 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using System.Text; 32using System.Text;
32using System.Text.RegularExpressions; 33using System.Text.RegularExpressions;
@@ -83,29 +84,56 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
83 m_console.Commands.AddCommand( 84 m_console.Commands.AddCommand(
84 "Objects", false, "delete object owner", 85 "Objects", false, "delete object owner",
85 "delete object owner <UUID>", 86 "delete object owner <UUID>",
86 "Delete a scene object by owner", HandleDeleteObject); 87 "Delete scene objects by owner",
88 "Command will ask for confirmation before proceeding.",
89 HandleDeleteObject);
87 90
88 m_console.Commands.AddCommand( 91 m_console.Commands.AddCommand(
89 "Objects", false, "delete object creator", 92 "Objects", false, "delete object creator",
90 "delete object creator <UUID>", 93 "delete object creator <UUID>",
91 "Delete a scene object by creator", HandleDeleteObject); 94 "Delete scene objects by creator",
95 "Command will ask for confirmation before proceeding.",
96 HandleDeleteObject);
92 97
93 m_console.Commands.AddCommand( 98 m_console.Commands.AddCommand(
94 "Objects", false, "delete object uuid", 99 "Objects", false, "delete object uuid",
95 "delete object uuid <UUID>", 100 "delete object uuid <UUID>",
96 "Delete a scene object by uuid", HandleDeleteObject); 101 "Delete a scene object by uuid",
102 HandleDeleteObject);
97 103
98 m_console.Commands.AddCommand( 104 m_console.Commands.AddCommand(
99 "Objects", false, "delete object name", 105 "Objects", false, "delete object name",
100 "delete object name [--regex] <name>", 106 "delete object name [--regex] <name>",
101 "Delete a scene object by name.", 107 "Delete a scene object by name.",
102 "If --regex is specified then the name is treatead as a regular expression", 108 "Command will ask for confirmation before proceeding.\n"
109 + "If --regex is specified then the name is treatead as a regular expression",
103 HandleDeleteObject); 110 HandleDeleteObject);
104 111
105 m_console.Commands.AddCommand( 112 m_console.Commands.AddCommand(
106 "Objects", false, "delete object outside", 113 "Objects", false, "delete object outside",
107 "delete object outside", 114 "delete object outside",
108 "Delete all scene objects outside region boundaries", HandleDeleteObject); 115 "Delete all scene objects outside region boundaries",
116 "Command will ask for confirmation before proceeding.",
117 HandleDeleteObject);
118
119 m_console.Commands.AddCommand(
120 "Objects",
121 false,
122 "delete object pos",
123 "delete object pos <start-coord> to <end-coord>",
124 "Delete scene objects within the given area.",
125 "Each component of the coord is comma separated. There must be no spaces between the commas.\n"
126 + "If you don't care about the z component you can simply omit it.\n"
127 + "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
128 + "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
129 + "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
130 + "e.g.\n"
131 + "delete object pos 20,20,20 to 40,40,40\n"
132 + "delete object pos 20,20 to 40,40\n"
133 + "delete object pos ,20,20 to ,40,40\n"
134 + "delete object pos ,,30 to ,,~\n"
135 + "delete object pos ,,-~ to ,,30",
136 HandleDeleteObject);
109 137
110 m_console.Commands.AddCommand( 138 m_console.Commands.AddCommand(
111 "Objects", 139 "Objects",
@@ -126,6 +154,25 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
126 m_console.Commands.AddCommand( 154 m_console.Commands.AddCommand(
127 "Objects", 155 "Objects",
128 false, 156 false,
157 "show object pos",
158 "show object pos <start-coord> to <end-coord>",
159 "Show details of scene objects within the given area.",
160 "Each component of the coord is comma separated. There must be no spaces between the commas.\n"
161 + "If you don't care about the z component you can simply omit it.\n"
162 + "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
163 + "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
164 + "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
165 + "e.g.\n"
166 + "show object pos 20,20,20 to 40,40,40\n"
167 + "show object pos 20,20 to 40,40\n"
168 + "show object pos ,20,20 to ,40,40\n"
169 + "show object pos ,,30 to ,,~\n"
170 + "show object pos ,,-~ to ,,30",
171 HandleShowObjectByPos);
172
173 m_console.Commands.AddCommand(
174 "Objects",
175 false,
129 "show part uuid", 176 "show part uuid",
130 "show part uuid <UUID>", 177 "show part uuid <UUID>",
131 "Show details of a scene object parts with the given UUID", HandleShowPartByUuid); 178 "Show details of a scene object parts with the given UUID", HandleShowPartByUuid);
@@ -138,6 +185,25 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
138 "Show details of scene object parts with the given name.", 185 "Show details of scene object parts with the given name.",
139 "If --regex is specified then the name is treatead as a regular expression", 186 "If --regex is specified then the name is treatead as a regular expression",
140 HandleShowPartByName); 187 HandleShowPartByName);
188
189 m_console.Commands.AddCommand(
190 "Objects",
191 false,
192 "show part pos",
193 "show part pos <start-coord> to <end-coord>",
194 "Show details of scene object parts within the given area.",
195 "Each component of the coord is comma separated. There must be no spaces between the commas.\n"
196 + "If you don't care about the z component you can simply omit it.\n"
197 + "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
198 + "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
199 + "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
200 + "e.g.\n"
201 + "show object pos 20,20,20 to 40,40,40\n"
202 + "show object pos 20,20 to 40,40\n"
203 + "show object pos ,20,20 to ,40,40\n"
204 + "show object pos ,,30 to ,,~\n"
205 + "show object pos ,,-~ to ,,30",
206 HandleShowPartByPos);
141 } 207 }
142 208
143 public void RemoveRegion(Scene scene) 209 public void RemoveRegion(Scene scene)
@@ -150,6 +216,43 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
150// m_log.DebugFormat("[OBJECTS COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 216// m_log.DebugFormat("[OBJECTS COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
151 } 217 }
152 218
219 private void OutputSogsToConsole(Predicate<SceneObjectGroup> searchPredicate)
220 {
221 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups().FindAll(searchPredicate);
222
223 StringBuilder sb = new StringBuilder();
224
225 foreach (SceneObjectGroup so in sceneObjects)
226 {
227 AddSceneObjectReport(sb, so);
228 sb.Append("\n");
229 }
230
231 sb.AppendFormat("{0} object(s) found in {1}\n", sceneObjects.Count, m_scene.Name);
232
233 m_console.OutputFormat(sb.ToString());
234 }
235
236 private void OutputSopsToConsole(Predicate<SceneObjectPart> searchPredicate)
237 {
238 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
239 List<SceneObjectPart> parts = new List<SceneObjectPart>();
240
241 sceneObjects.ForEach(so => parts.AddRange(Array.FindAll<SceneObjectPart>(so.Parts, searchPredicate)));
242
243 StringBuilder sb = new StringBuilder();
244
245 foreach (SceneObjectPart part in parts)
246 {
247 AddScenePartReport(sb, part);
248 sb.Append("\n");
249 }
250
251 sb.AppendFormat("{0} parts found in {1}\n", parts.Count, m_scene.Name);
252
253 m_console.OutputFormat(sb.ToString());
254 }
255
153 private void HandleShowObjectByUuid(string module, string[] cmd) 256 private void HandleShowObjectByUuid(string module, string[] cmd)
154 { 257 {
155 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) 258 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
@@ -200,36 +303,41 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
200 303
201 string name = mainParams[3]; 304 string name = mainParams[3];
202 305
203 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 306 Predicate<SceneObjectGroup> searchPredicate;
204 Action<SceneObjectGroup> searchAction;
205 307
206 if (useRegex) 308 if (useRegex)
207 { 309 {
208 Regex nameRegex = new Regex(name); 310 Regex nameRegex = new Regex(name);
209 searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; 311 searchPredicate = so => nameRegex.IsMatch(so.Name);
210 } 312 }
211 else 313 else
212 { 314 {
213 searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; 315 searchPredicate = so => so.Name == name;
214 } 316 }
215 317
216 m_scene.ForEachSOG(searchAction); 318 OutputSogsToConsole(searchPredicate);
319 }
217 320
218 if (sceneObjects.Count == 0) 321 private void HandleShowObjectByPos(string module, string[] cmdparams)
322 {
323 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
324 return;
325
326 if (cmdparams.Length < 5)
219 { 327 {
220 m_console.OutputFormat("No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName); 328 m_console.OutputFormat("Usage: show object pos <start-coord> to <end-coord>");
221 return; 329 return;
222 } 330 }
223 331
224 StringBuilder sb = new StringBuilder(); 332 Vector3 startVector, endVector;
225 333
226 foreach (SceneObjectGroup so in sceneObjects) 334 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
227 { 335 return;
228 AddSceneObjectReport(sb, so);
229 sb.Append("\n");
230 }
231 336
232 m_console.OutputFormat(sb.ToString()); 337 Predicate<SceneObjectGroup> searchPredicate
338 = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
339
340 OutputSogsToConsole(searchPredicate);
233 } 341 }
234 342
235 private void HandleShowPartByUuid(string module, string[] cmd) 343 private void HandleShowPartByUuid(string module, string[] cmd)
@@ -264,6 +372,38 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
264 m_console.OutputFormat(sb.ToString()); 372 m_console.OutputFormat(sb.ToString());
265 } 373 }
266 374
375 private void HandleShowPartByPos(string module, string[] cmdparams)
376 {
377 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
378 return;
379
380 if (cmdparams.Length < 5)
381 {
382 m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
383 return;
384 }
385
386 string rawConsoleStartVector = cmdparams[3];
387 Vector3 startVector;
388
389 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
390 {
391 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
392 return;
393 }
394
395 string rawConsoleEndVector = cmdparams[5];
396 Vector3 endVector;
397
398 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
399 {
400 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
401 return;
402 }
403
404 OutputSopsToConsole(sop => Util.IsInsideBox(sop.AbsolutePosition, startVector, endVector));
405 }
406
267 private void HandleShowPartByName(string module, string[] cmdparams) 407 private void HandleShowPartByName(string module, string[] cmdparams)
268 { 408 {
269 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) 409 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
@@ -282,37 +422,19 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
282 422
283 string name = mainParams[3]; 423 string name = mainParams[3];
284 424
285 List<SceneObjectPart> parts = new List<SceneObjectPart>(); 425 Predicate<SceneObjectPart> searchPredicate;
286
287 Action<SceneObjectGroup> searchAction;
288 426
289 if (useRegex) 427 if (useRegex)
290 { 428 {
291 Regex nameRegex = new Regex(name); 429 Regex nameRegex = new Regex(name);
292 searchAction = so => so.ForEachPart(sop => { if (nameRegex.IsMatch(sop.Name)) { parts.Add(sop); } }); 430 searchPredicate = sop => nameRegex.IsMatch(sop.Name);
293 } 431 }
294 else 432 else
295 { 433 {
296 searchAction = so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } }); 434 searchPredicate = sop => sop.Name == name;
297 }
298
299 m_scene.ForEachSOG(searchAction);
300
301 if (parts.Count == 0)
302 {
303 m_console.OutputFormat("No parts with name {0} found in {1}", name, m_scene.RegionInfo.RegionName);
304 return;
305 }
306
307 StringBuilder sb = new StringBuilder();
308
309 foreach (SceneObjectPart part in parts)
310 {
311 AddScenePartReport(sb, part);
312 sb.Append("\n");
313 } 435 }
314 436
315 m_console.OutputFormat(sb.ToString()); 437 OutputSopsToConsole(searchPredicate);
316 } 438 }
317 439
318 private StringBuilder AddSceneObjectReport(StringBuilder sb, SceneObjectGroup so) 440 private StringBuilder AddSceneObjectReport(StringBuilder sb, SceneObjectGroup so)
@@ -450,6 +572,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
450 572
451 break; 573 break;
452 574
575 case "pos":
576 deletes = GetDeleteCandidatesByPos(module, cmd);
577 break;
578
453 default: 579 default:
454 m_console.OutputFormat("Unrecognized mode {0}", mode); 580 m_console.OutputFormat("Unrecognized mode {0}", mode);
455 return; 581 return;
@@ -464,7 +590,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
464 string.Format( 590 string.Format(
465 "Are you sure that you want to delete {0} objects from {1}", 591 "Are you sure that you want to delete {0} objects from {1}",
466 deletes.Count, m_scene.RegionInfo.RegionName), 592 deletes.Count, m_scene.RegionInfo.RegionName),
467 "n"); 593 "y/N");
468 594
469 if (response.ToLower() != "y") 595 if (response.ToLower() != "y")
470 { 596 {
@@ -486,9 +612,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
486 612
487 private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams) 613 private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
488 { 614 {
489 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
490 return null;
491
492 bool useRegex = false; 615 bool useRegex = false;
493 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); 616 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
494 617
@@ -522,5 +645,52 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
522 645
523 return sceneObjects; 646 return sceneObjects;
524 } 647 }
648
649 /// <summary>
650 /// Get scene object delete candidates by position
651 /// </summary>
652 /// <param name='module'></param>
653 /// <param name='cmdparams'></param>
654 /// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
655 /// are no objects to delete then the list will be empty./returns>
656 private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
657 {
658 if (cmdparams.Length < 5)
659 {
660 m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
661 return null;
662 }
663
664 Vector3 startVector, endVector;
665
666 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
667 return null;
668
669 return m_scene.GetSceneObjectGroups().FindAll(
670 so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
671 }
672
673 private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
674 {
675 string rawConsoleStartVector = rawComponents.Take(1).Single();
676
677 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
678 {
679 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
680 endVector = Vector3.Zero;
681
682 return false;
683 }
684
685 string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single();
686
687 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
688 {
689 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
690 return false;
691 }
692
693 return true;
694 }
525 } 695 }
526} \ No newline at end of file 696} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 14c1a39..a2f0950 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -85,13 +85,15 @@ namespace OpenSim.Region.CoreModules.World.Sound
85 dis = 0; 85 dis = 0;
86 } 86 }
87 87
88 float thisSpGain;
89
88 // Scale by distance 90 // Scale by distance
89 if (radius == 0) 91 if (radius == 0)
90 gain = (float)((double)gain * ((100.0 - dis) / 100.0)); 92 thisSpGain = (float)((double)gain * ((100.0 - dis) / 100.0));
91 else 93 else
92 gain = (float)((double)gain * ((radius - dis) / radius)); 94 thisSpGain = (float)((double)gain * ((radius - dis) / radius));
93 95
94 sp.ControllingClient.SendPlayAttachedSound(soundID, objectID, ownerID, (float)gain, flags); 96 sp.ControllingClient.SendPlayAttachedSound(soundID, objectID, ownerID, thisSpGain, flags);
95 }); 97 });
96 } 98 }
97 99
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 402b9fb..d99567c 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -414,6 +414,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
414 private void LoadPlugins() 414 private void LoadPlugins()
415 { 415 {
416 m_plugineffects = new Dictionary<string, ITerrainEffect>(); 416 m_plugineffects = new Dictionary<string, ITerrainEffect>();
417 LoadPlugins(Assembly.GetCallingAssembly());
417 string plugineffectsPath = "Terrain"; 418 string plugineffectsPath = "Terrain";
418 419
419 // Load the files in the Terrain/ dir 420 // Load the files in the Terrain/ dir
@@ -427,34 +428,39 @@ namespace OpenSim.Region.CoreModules.World.Terrain
427 try 428 try
428 { 429 {
429 Assembly library = Assembly.LoadFrom(file); 430 Assembly library = Assembly.LoadFrom(file);
430 foreach (Type pluginType in library.GetTypes()) 431 LoadPlugins(library);
431 { 432 }
432 try 433 catch (BadImageFormatException)
433 { 434 {
434 if (pluginType.IsAbstract || pluginType.IsNotPublic) 435 }
435 continue; 436 }
437 }
436 438
437 string typeName = pluginType.Name; 439 private void LoadPlugins(Assembly library)
440 {
441 foreach (Type pluginType in library.GetTypes())
442 {
443 try
444 {
445 if (pluginType.IsAbstract || pluginType.IsNotPublic)
446 continue;
438 447
439 if (pluginType.GetInterface("ITerrainEffect", false) != null) 448 string typeName = pluginType.Name;
440 {
441 ITerrainEffect terEffect = (ITerrainEffect) Activator.CreateInstance(library.GetType(pluginType.ToString()));
442 449
443 InstallPlugin(typeName, terEffect); 450 if (pluginType.GetInterface("ITerrainEffect", false) != null)
444 } 451 {
445 else if (pluginType.GetInterface("ITerrainLoader", false) != null) 452 ITerrainEffect terEffect = (ITerrainEffect)Activator.CreateInstance(library.GetType(pluginType.ToString()));
446 { 453
447 ITerrainLoader terLoader = (ITerrainLoader) Activator.CreateInstance(library.GetType(pluginType.ToString())); 454 InstallPlugin(typeName, terEffect);
448 m_loaders[terLoader.FileExtension] = terLoader; 455 }
449 m_log.Info("L ... " + typeName); 456 else if (pluginType.GetInterface("ITerrainLoader", false) != null)
450 } 457 {
451 } 458 ITerrainLoader terLoader = (ITerrainLoader)Activator.CreateInstance(library.GetType(pluginType.ToString()));
452 catch (AmbiguousMatchException) 459 m_loaders[terLoader.FileExtension] = terLoader;
453 { 460 m_log.Info("L ... " + typeName);
454 }
455 } 461 }
456 } 462 }
457 catch (BadImageFormatException) 463 catch (AmbiguousMatchException)
458 { 464 {
459 } 465 }
460 } 466 }
@@ -1178,7 +1184,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1178 1184
1179 private void InterfaceRunPluginEffect(Object[] args) 1185 private void InterfaceRunPluginEffect(Object[] args)
1180 { 1186 {
1181 if ((string) args[0] == "list") 1187 string firstArg = (string)args[0];
1188 if (firstArg == "list")
1182 { 1189 {
1183 m_log.Info("List of loaded plugins"); 1190 m_log.Info("List of loaded plugins");
1184 foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) 1191 foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
@@ -1187,14 +1194,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1187 } 1194 }
1188 return; 1195 return;
1189 } 1196 }
1190 if ((string) args[0] == "reload") 1197 if (firstArg == "reload")
1191 { 1198 {
1192 LoadPlugins(); 1199 LoadPlugins();
1193 return; 1200 return;
1194 } 1201 }
1195 if (m_plugineffects.ContainsKey((string) args[0])) 1202 if (m_plugineffects.ContainsKey(firstArg))
1196 { 1203 {
1197 m_plugineffects[(string) args[0]].RunEffect(m_channel); 1204 m_plugineffects[firstArg].RunEffect(m_channel);
1198 CheckForTerrainUpdates(); 1205 CheckForTerrainUpdates();
1199 } 1206 }
1200 else 1207 else
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
index 3c48d07..33f6c3f 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
@@ -222,6 +222,13 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
222 bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height); 222 bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height);
223 } 223 }
224 224
225 // XXX: It shouldn't really be necesary to force a GC here as one should occur anyway pretty shortly
226 // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory
227 // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating
228 // this map tile simply takes a lot of memory.
229 GC.Collect();
230 m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
231
225 return bitmap; 232 return bitmap;
226 } 233 }
227 234
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 90a13a7..d781eae 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -114,6 +114,15 @@ namespace OpenSim.Region.Framework.Interfaces
114 void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID); 114 void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID);
115 115
116 /// <summary> 116 /// <summary>
117 /// Detach the given item to the ground at the specified coordinates & rotation
118 /// </summary>
119 /// <param name="sp"></param>
120 /// <param name="objectLocalID"></param>
121 /// <param name="absolutePos"></param>
122 /// <param name="absoluteRot"></param>
123 void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID, Vector3 absolutePos, Quaternion absoluteRot);
124
125 /// <summary>
117 /// Detach the given attachment so that it remains in the user's inventory. 126 /// Detach the given attachment so that it remains in the user's inventory.
118 /// </summary> 127 /// </summary>
119 /// <param name="sp">/param> 128 /// <param name="sp">/param>
diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
index 8954513..6df5cc2 100644
--- a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
+++ b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs
@@ -25,6 +25,8 @@
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;
29using System.Drawing;
28using System.IO; 30using System.IO;
29using OpenMetaverse; 31using OpenMetaverse;
30 32
@@ -33,7 +35,14 @@ namespace OpenSim.Region.Framework.Interfaces
33 public interface IDynamicTextureManager 35 public interface IDynamicTextureManager
34 { 36 {
35 void RegisterRender(string handleType, IDynamicTextureRender render); 37 void RegisterRender(string handleType, IDynamicTextureRender render);
36 void ReturnData(UUID id, byte[] data); 38
39 /// <summary>
40 /// Used by IDynamicTextureRender implementations to return renders
41 /// </summary>
42 /// <param name='id'></param>
43 /// <param name='data'></param>
44 /// <param name='isReuseable'></param>
45 void ReturnData(UUID id, IDynamicTexture texture);
37 46
38 UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, 47 UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams,
39 int updateTimer); 48 int updateTimer);
@@ -113,11 +122,65 @@ namespace OpenSim.Region.Framework.Interfaces
113 string GetName(); 122 string GetName();
114 string GetContentType(); 123 string GetContentType();
115 bool SupportsAsynchronous(); 124 bool SupportsAsynchronous();
116 byte[] ConvertUrl(string url, string extraParams); 125
117 byte[] ConvertStream(Stream data, string extraParams); 126// /// <summary>
127// /// Return true if converting the input body and extra params data will always result in the same byte[] array
128// /// </summary>
129// /// <remarks>
130// /// This method allows the caller to use a previously generated asset if it has one.
131// /// </remarks>
132// /// <returns></returns>
133// /// <param name='bodyData'></param>
134// /// <param name='extraParams'></param>
135// bool AlwaysIdenticalConversion(string bodyData, string extraParams);
136
137 IDynamicTexture ConvertUrl(string url, string extraParams);
138 IDynamicTexture ConvertData(string bodyData, string extraParams);
139
118 bool AsyncConvertUrl(UUID id, string url, string extraParams); 140 bool AsyncConvertUrl(UUID id, string url, string extraParams);
119 bool AsyncConvertData(UUID id, string bodyData, string extraParams); 141 bool AsyncConvertData(UUID id, string bodyData, string extraParams);
142
120 void GetDrawStringSize(string text, string fontName, int fontSize, 143 void GetDrawStringSize(string text, string fontName, int fontSize,
121 out double xSize, out double ySize); 144 out double xSize, out double ySize);
122 } 145 }
146
147 public interface IDynamicTexture
148 {
149 /// <summary>
150 /// Input commands used to generate this data.
151 /// </summary>
152 /// <remarks>
153 /// Null if input commands were not used.
154 /// </remarks>
155 string InputCommands { get; }
156
157 /// <summary>
158 /// Uri used to generate this data.
159 /// </summary>
160 /// <remarks>
161 /// Null if a uri was not used.
162 /// </remarks>
163 Uri InputUri { get; }
164
165 /// <summary>
166 /// Extra input params used to generate this data.
167 /// </summary>
168 string InputParams { get; }
169
170 /// <summary>
171 /// Texture data.
172 /// </summary>
173 byte[] Data { get; }
174
175 /// <summary>
176 /// Size of texture.
177 /// </summary>
178 Size Size { get; }
179
180 /// <summary>
181 /// Signal whether the texture is reuseable (i.e. whether the same input data will always generate the same
182 /// texture).
183 /// </summary>
184 bool IsReuseable { get; }
185 }
123} 186}
diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
index ca2ad94..292efa4 100644
--- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
@@ -46,6 +46,10 @@ namespace OpenSim.Region.Framework.Interfaces
46 /// </summary> 46 /// </summary>
47 void sendRegionHandshakeToAll(); 47 void sendRegionHandshakeToAll();
48 void TriggerEstateInfoChange(); 48 void TriggerEstateInfoChange();
49
50 /// <summary>
51 /// Fires the OnRegionInfoChange event.
52 /// </summary>
49 void TriggerRegionInfoChange(); 53 void TriggerRegionInfoChange();
50 54
51 void setEstateTerrainBaseTexture(int level, UUID texture); 55 void setEstateTerrainBaseTexture(int level, UUID texture);
diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
index baac6e8..da39e95 100644
--- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs
@@ -35,7 +35,7 @@ namespace OpenSim.Region.Framework.Interfaces
35 35
36 public interface IJsonStoreModule 36 public interface IJsonStoreModule
37 { 37 {
38 bool CreateStore(string value, out UUID result); 38 bool CreateStore(string value, ref UUID result);
39 bool DestroyStore(UUID storeID); 39 bool DestroyStore(UUID storeID);
40 bool TestPath(UUID storeID, string path, bool useJson); 40 bool TestPath(UUID storeID, string path, bool useJson);
41 bool SetValue(UUID storeID, string path, string value, bool useJson); 41 bool SetValue(UUID storeID, string path, string value, bool useJson);
diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs b/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
index ed71a95..93930ce 100644
--- a/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScriptModuleComms.cs
@@ -46,9 +46,46 @@ namespace OpenSim.Region.Framework.Interfaces
46 /// </summary> 46 /// </summary>
47 event ScriptCommand OnScriptCommand; 47 event ScriptCommand OnScriptCommand;
48 48
49 /// <summary>
50 /// Register an instance method as a script call by method name
51 /// </summary>
52 /// <param name="target"></param>
53 /// <param name="method"></param>
49 void RegisterScriptInvocation(object target, string method); 54 void RegisterScriptInvocation(object target, string method);
55
56 /// <summary>
57 /// Register a static or instance method as a script call by method info
58 /// </summary>
59 /// <param name="target">If target is a Type object, will assume method is static.</param>
60 /// <param name="method"></param>
50 void RegisterScriptInvocation(object target, MethodInfo method); 61 void RegisterScriptInvocation(object target, MethodInfo method);
62
63 /// <summary>
64 /// Register one or more instance methods as script calls by method name
65 /// </summary>
66 /// <param name="target"></param>
67 /// <param name="methods"></param>
51 void RegisterScriptInvocation(object target, string[] methods); 68 void RegisterScriptInvocation(object target, string[] methods);
69
70 /// <summary>
71 /// Register one or more static methods as script calls by method name
72 /// </summary>
73 /// <param name="target"></param>
74 /// <param name="methods"></param>
75 void RegisterScriptInvocation(Type target, string[] methods);
76
77 /// <summary>
78 /// Automatically register script invocations by checking for methods
79 /// with <see cref="ScriptInvocationAttribute"/>. Should only check
80 /// public methods.
81 /// </summary>
82 /// <param name="target"></param>
83 void RegisterScriptInvocations(IRegionModuleBase target);
84
85 /// <summary>
86 /// Returns an array of all registered script calls
87 /// </summary>
88 /// <returns></returns>
52 Delegate[] GetScriptInvocationList(); 89 Delegate[] GetScriptInvocationList();
53 90
54 Delegate LookupScriptInvocation(string fname); 91 Delegate LookupScriptInvocation(string fname);
@@ -67,11 +104,43 @@ namespace OpenSim.Region.Framework.Interfaces
67 /// <param name="key"></param> 104 /// <param name="key"></param>
68 void DispatchReply(UUID scriptId, int code, string text, string key); 105 void DispatchReply(UUID scriptId, int code, string text, string key);
69 106
70 /// For constants 107 /// <summary>
108 /// Operation to for a region module to register a constant to be used
109 /// by the script engine
110 /// </summary>
111 /// <param name="cname">
112 /// The name of the constant. LSL convention is for constant names to
113 /// be uppercase.
114 /// </param>
115 /// <param name="value">
116 /// The value of the constant. Should be of a type that can be
117 /// converted to one of <see cref="OpenSim.Region.ScriptEngine.Shared.LSL_Types"/>
118 /// </param>
71 void RegisterConstant(string cname, object value); 119 void RegisterConstant(string cname, object value);
120
121 /// <summary>
122 /// Automatically register all constants on a region module by
123 /// checking for fields with <see cref="ScriptConstantAttribute"/>.
124 /// </summary>
125 /// <param name="target"></param>
126 void RegisterConstants(IRegionModuleBase target);
127
128 /// <summary>
129 /// Operation to check for a registered constant
130 /// </summary>
131 /// <param name="cname">Name of constant</param>
132 /// <returns>Value of constant or null if none found.</returns>
72 object LookupModConstant(string cname); 133 object LookupModConstant(string cname);
73 134
74 // For use ONLY by the script API 135 // For use ONLY by the script API
75 void RaiseEvent(UUID script, string id, string module, string command, string key); 136 void RaiseEvent(UUID script, string id, string module, string command, string key);
76 } 137 }
138
139 [AttributeUsage(AttributeTargets.Method)]
140 public class ScriptInvocationAttribute : Attribute
141 { }
142
143 [AttributeUsage(AttributeTargets.Field)]
144 public class ScriptConstantAttribute : Attribute
145 { }
77} 146}
diff --git a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs
index 457444c..79e9f9d 100644
--- a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs
@@ -39,6 +39,8 @@ namespace OpenSim.Region.Framework.Interfaces
39 UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID); 39 UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID);
40 void ReleaseURL(string url); 40 void ReleaseURL(string url);
41 void HttpResponse(UUID request, int status, string body); 41 void HttpResponse(UUID request, int status, string body);
42 void HttpContentType(UUID request, string type);
43
42 string GetHttpHeader(UUID request, string header); 44 string GetHttpHeader(UUID request, string header);
43 int GetFreeUrls(); 45 int GetFreeUrls();
44 46
diff --git a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs
index 24cd069..f8088c3 100644
--- a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs
+++ b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs
@@ -1,4 +1,31 @@
1using System; 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;
2using System.Collections.Generic; 29using System.Collections.Generic;
3 30
4using OpenMetaverse; 31using OpenMetaverse;
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index eee5960..e2414eb 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -47,30 +47,75 @@ namespace OpenSim.Region.Framework.Scenes
47 47
48 public delegate void OnFrameDelegate(); 48 public delegate void OnFrameDelegate();
49 49
50 /// <summary>
51 /// Triggered on each sim frame.
52 /// </summary>
53 /// <remarks>
54 /// This gets triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.Update"/>
55 /// Core uses it for things like Sun, Wind & Clouds
56 /// The MRM module also uses it.
57 /// </remarks>
50 public event OnFrameDelegate OnFrame; 58 public event OnFrameDelegate OnFrame;
51 59
52 public delegate void ClientMovement(ScenePresence client); 60 public delegate void ClientMovement(ScenePresence client);
53 61
62 /// <summary>
63 /// Trigerred when an agent moves.
64 /// </summary>
65 /// <remarks>
66 /// This gets triggered in <see cref="OpenSim.Region.Framework.Scenes.ScenePresence.HandleAgentUpdate"/>
67 /// prior to <see cref="OpenSim.Region.Framework.Scenes.ScenePresence.TriggerScenePresenceUpdated"/>
68 /// </remarks>
54 public event ClientMovement OnClientMovement; 69 public event ClientMovement OnClientMovement;
55 70
56 public delegate void OnTerrainTaintedDelegate(); 71 public delegate void OnTerrainTaintedDelegate();
57 72
73 /// <summary>
74 /// Triggered if the terrain has been edited
75 /// </summary>
76 /// <remarks>
77 /// This gets triggered in <see cref="OpenSim.Region.CoreModules.World.Terrain.CheckForTerrainUpdates"/>
78 /// after it determines that an update has been made.
79 /// </remarks>
58 public event OnTerrainTaintedDelegate OnTerrainTainted; 80 public event OnTerrainTaintedDelegate OnTerrainTainted;
59 81
60 public delegate void OnTerrainTickDelegate(); 82 public delegate void OnTerrainTickDelegate();
61 83
62 public delegate void OnTerrainUpdateDelegate(); 84 /// <summary>
63 85 /// Triggered if the terrain has been edited
86 /// </summary>
87 /// <remarks>
88 /// This gets triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.UpdateTerrain"/>
89 /// but is used by core solely to update the physics engine.
90 /// </remarks>
64 public event OnTerrainTickDelegate OnTerrainTick; 91 public event OnTerrainTickDelegate OnTerrainTick;
65 92
93 public delegate void OnTerrainUpdateDelegate();
94
66 public event OnTerrainUpdateDelegate OnTerrainUpdate; 95 public event OnTerrainUpdateDelegate OnTerrainUpdate;
67 96
68 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup); 97 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup);
69 98
99 /// <summary>
100 /// Triggered when a region is backed up/persisted to storage
101 /// </summary>
102 /// <remarks>
103 /// This gets triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.Backup"/>
104 /// and is fired before the persistence occurs.
105 /// </remarks>
70 public event OnBackupDelegate OnBackup; 106 public event OnBackupDelegate OnBackup;
71 107
72 public delegate void OnClientConnectCoreDelegate(IClientCore client); 108 public delegate void OnClientConnectCoreDelegate(IClientCore client);
73 109
110 /// <summary>
111 /// Triggered when a new client connects to the scene.
112 /// </summary>
113 /// <remarks>
114 /// This gets triggered in <see cref="TriggerOnNewClient"/>,
115 /// which checks if an instance of <see cref="OpenSim.Framework.IClientAPI"/>
116 /// also implements <see cref="OpenSim.Framework.Client.IClientCore"/> and as such,
117 /// is not triggered by <see cref="OpenSim.Region.OptionalModules.World.NPC">NPCs</see>.
118 /// </remarks>
74 public event OnClientConnectCoreDelegate OnClientConnect; 119 public event OnClientConnectCoreDelegate OnClientConnect;
75 120
76 public delegate void OnNewClientDelegate(IClientAPI client); 121 public delegate void OnNewClientDelegate(IClientAPI client);
@@ -80,33 +125,96 @@ namespace OpenSim.Region.Framework.Scenes
80 /// </summary> 125 /// </summary>
81 /// <remarks> 126 /// <remarks>
82 /// This is triggered for both child and root agent client connections. 127 /// This is triggered for both child and root agent client connections.
128 ///
83 /// Triggered before OnClientLogin. 129 /// Triggered before OnClientLogin.
130 ///
131 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
132 /// do this on a separate thread.
84 /// </remarks> 133 /// </remarks>
85 public event OnNewClientDelegate OnNewClient; 134 public event OnNewClientDelegate OnNewClient;
86 135
87 /// <summary> 136 /// <summary>
88 /// Fired if the client entering this sim is doing so as a new login 137 /// Fired if the client entering this sim is doing so as a new login
89 /// </summary> 138 /// </summary>
139 /// <remarks>
140 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
141 /// do this on a separate thread.
142 /// </remarks>
90 public event Action<IClientAPI> OnClientLogin; 143 public event Action<IClientAPI> OnClientLogin;
91 144
92 public delegate void OnNewPresenceDelegate(ScenePresence presence); 145 public delegate void OnNewPresenceDelegate(ScenePresence presence);
93 146
147 /// <summary>
148 /// Triggered when a new presence is added to the scene
149 /// </summary>
150 /// <remarks>
151 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both
152 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
153 /// </remarks>
94 public event OnNewPresenceDelegate OnNewPresence; 154 public event OnNewPresenceDelegate OnNewPresence;
95 155
96 public delegate void OnRemovePresenceDelegate(UUID agentId); 156 public delegate void OnRemovePresenceDelegate(UUID agentId);
97 157
158 /// <summary>
159 /// Triggered when a presence is removed from the scene
160 /// </summary>
161 /// <remarks>
162 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both
163 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
164 ///
165 /// Triggered under per-agent lock. So if you want to perform any long-running operations, please
166 /// do this on a separate thread.
167 /// </remarks>
98 public event OnRemovePresenceDelegate OnRemovePresence; 168 public event OnRemovePresenceDelegate OnRemovePresence;
99 169
100 public delegate void OnParcelPrimCountUpdateDelegate(); 170 public delegate void OnParcelPrimCountUpdateDelegate();
101 171
172 /// <summary>
173 /// Triggered whenever the prim count may have been altered, or prior
174 /// to an action that requires the current prim count to be accurate.
175 /// </summary>
176 /// <remarks>
177 /// Triggered by <see cref="TriggerParcelPrimCountUpdate"/> in
178 /// <see cref="OpenSim.OpenSimBase.CreateRegion"/>,
179 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandManagementModule.EventManagerOnRequestParcelPrimCountUpdate"/>,
180 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandManagementModule.ClientOnParcelObjectOwnerRequest"/>,
181 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandObject.GetPrimsFree"/>,
182 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandObject.UpdateLandSold"/>,
183 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandObject.DeedToGroup"/>,
184 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandObject.SendLandUpdateToClient"/>
185 /// </remarks>
102 public event OnParcelPrimCountUpdateDelegate OnParcelPrimCountUpdate; 186 public event OnParcelPrimCountUpdateDelegate OnParcelPrimCountUpdate;
103 187
104 public delegate void OnParcelPrimCountAddDelegate(SceneObjectGroup obj); 188 public delegate void OnParcelPrimCountAddDelegate(SceneObjectGroup obj);
105 189
190 /// <summary>
191 /// Triggered in response to <see cref="OnParcelPrimCountUpdate"/> for
192 /// objects that actually contribute to parcel prim count.
193 /// </summary>
194 /// <remarks>
195 /// Triggered by <see cref="TriggerParcelPrimCountAdd"/> in
196 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandManagementModule.EventManagerOnParcelPrimCountUpdate"/>
197 /// </remarks>
106 public event OnParcelPrimCountAddDelegate OnParcelPrimCountAdd; 198 public event OnParcelPrimCountAddDelegate OnParcelPrimCountAdd;
107 199
108 public delegate void OnPluginConsoleDelegate(string[] args); 200 public delegate void OnPluginConsoleDelegate(string[] args);
109 201
202 /// <summary>
203 /// Triggered after <see cref="OpenSim.IApplicationPlugin.PostInitialise"/>
204 /// has been called for all <see cref="OpenSim.IApplicationPlugin"/>
205 /// loaded via <see cref="OpenSim.OpenSimBase.LoadPlugins"/>.
206 /// Handlers for this event are typically used to parse the arguments
207 /// from <see cref="OnPluginConsoleDelegate"/> in order to process or
208 /// filter the arguments and pass them onto <see cref="OpenSim.Region.CoreModules.Framework.InterfaceCommander.Commander.ProcessConsoleCommand"/>
209 /// </summary>
210 /// <remarks>
211 /// Triggered by <see cref="TriggerOnPluginConsole"/> in
212 /// <see cref="Scene.SendCommandToPlugins"/> via
213 /// <see cref="SceneManager.SendCommandToPluginModules"/> via
214 /// <see cref="OpenSim.OpenSimBase.HandleCommanderCommand"/> via
215 /// <see cref="OpenSim.OpenSimBase.AddPluginCommands"/> via
216 /// <see cref="OpenSim.OpenSimBase.StartupSpecific"/>
217 /// </remarks>
110 public event OnPluginConsoleDelegate OnPluginConsole; 218 public event OnPluginConsoleDelegate OnPluginConsole;
111 219
112 /// <summary> 220 /// <summary>
@@ -121,8 +229,28 @@ namespace OpenSim.Region.Framework.Scenes
121 229
122 public delegate void OnSetRootAgentSceneDelegate(UUID agentID, Scene scene); 230 public delegate void OnSetRootAgentSceneDelegate(UUID agentID, Scene scene);
123 231
232 /// <summary>
233 /// Triggered before the grunt work for adding a root agent to a
234 /// scene has been performed (resuming attachment scripts, physics,
235 /// animations etc.)
236 /// </summary>
237 /// <remarks>
238 /// Triggered before <see cref="OnMakeRootAgent"/>
239 /// by <see cref="TriggerSetRootAgentScene"/>
240 /// in <see cref="ScenePresence.MakeRootAgent"/>
241 /// via <see cref="Scene.AgentCrossing"/>
242 /// and <see cref="ScenePresence.CompleteMovement"/>
243 /// </remarks>
124 public event OnSetRootAgentSceneDelegate OnSetRootAgentScene; 244 public event OnSetRootAgentSceneDelegate OnSetRootAgentScene;
125 245
246 /// <summary>
247 /// Triggered after parcel properties have been updated.
248 /// </summary>
249 /// <remarks>
250 /// Triggered by <see cref="TriggerOnParcelPropertiesUpdateRequest"/> in
251 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandManagementModule.ClientOnParcelPropertiesUpdateRequest"/>,
252 /// <see cref="OpenSim.Region.CoreModules.World.Land.LandManagementModule.ProcessPropertiesUpdate"/>
253 /// </remarks>
126 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; 254 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
127 255
128 /// <summary> 256 /// <summary>
@@ -137,13 +265,45 @@ namespace OpenSim.Region.Framework.Scenes
137 /// <summary> 265 /// <summary>
138 /// Fired when an object is touched/grabbed. 266 /// Fired when an object is touched/grabbed.
139 /// </summary> 267 /// </summary>
268 /// <remarks>
140 /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of 269 /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of
141 /// the root part. 270 /// the root part.
271 /// Triggerd in response to <see cref="OpenSim.Framework.IClientAPI.OnGrabObject"/>
272 /// via <see cref="TriggerObjectGrab"/>
273 /// in <see cref="Scene.ProcessObjectGrab"/>
274 /// </remarks>
142 public event ObjectGrabDelegate OnObjectGrab; 275 public event ObjectGrabDelegate OnObjectGrab;
143 public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); 276 public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs);
144 277
278 /// <summary>
279 /// Triggered when an object is being touched/grabbed continuously.
280 /// </summary>
281 /// <remarks>
282 /// Triggered in response to <see cref="OpenSim.Framework.IClientAPI.OnGrabUpdate"/>
283 /// via <see cref="TriggerObjectGrabbing"/>
284 /// in <see cref="Scene.ProcessObjectGrabUpdate"/>
285 /// </remarks>
145 public event ObjectGrabDelegate OnObjectGrabbing; 286 public event ObjectGrabDelegate OnObjectGrabbing;
287
288 /// <summary>
289 /// Triggered when an object stops being touched/grabbed.
290 /// </summary>
291 /// <remarks>
292 /// Triggered in response to <see cref="OpenSim.Framework.IClientAPI.OnDeGrabObject"/>
293 /// via <see cref="TriggerObjectDeGrab"/>
294 /// in <see cref="Scene.ProcessObjectDeGrab"/>
295 /// </remarks>
146 public event ObjectDeGrabDelegate OnObjectDeGrab; 296 public event ObjectDeGrabDelegate OnObjectDeGrab;
297
298 /// <summary>
299 /// Triggered when a script resets.
300 /// </summary>
301 /// <remarks>
302 /// Triggered by <see cref="TriggerScriptReset"/>
303 /// in <see cref="Scene.ProcessScriptReset"/>
304 /// via <see cref="OpenSim.Framework.IClientAPI.OnScriptReset"/>
305 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleScriptReset"/>
306 /// </remarks>
147 public event ScriptResetDelegate OnScriptReset; 307 public event ScriptResetDelegate OnScriptReset;
148 308
149 public event OnPermissionErrorDelegate OnPermissionError; 309 public event OnPermissionErrorDelegate OnPermissionError;
@@ -153,29 +313,105 @@ namespace OpenSim.Region.Framework.Scenes
153 /// </summary> 313 /// </summary>
154 /// <remarks> 314 /// <remarks>
155 /// Occurs after OnNewScript. 315 /// Occurs after OnNewScript.
316 /// Triggered by <see cref="TriggerRezScript"/>
317 /// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>
156 /// </remarks> 318 /// </remarks>
157 public event NewRezScript OnRezScript; 319 public event NewRezScript OnRezScript;
158 public delegate void NewRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource); 320 public delegate void NewRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource);
159 321
160 public delegate void RemoveScript(uint localID, UUID itemID); 322 public delegate void RemoveScript(uint localID, UUID itemID);
323
324 /// <summary>
325 /// Triggered when a script is removed from an object.
326 /// </summary>
327 /// <remarks>
328 /// Triggered by <see cref="TriggerRemoveScript"/>
329 /// in <see cref="Scene.RemoveTaskInventory"/>,
330 /// <see cref="Scene.CreateAgentInventoryItemFromTask"/>,
331 /// <see cref="SceneObjectPartInventory.RemoveScriptInstance"/>,
332 /// <see cref="SceneObjectPartInventory.RemoveInventoryItem"/>
333 /// </remarks>
161 public event RemoveScript OnRemoveScript; 334 public event RemoveScript OnRemoveScript;
162 335
163 public delegate void StartScript(uint localID, UUID itemID); 336 public delegate void StartScript(uint localID, UUID itemID);
337
338 /// <summary>
339 /// Triggered when a script starts.
340 /// </summary>
341 /// <remarks>
342 /// Triggered by <see cref="TriggerStartScript"/>
343 /// in <see cref="Scene.SetScriptRunning"/>
344 /// via <see cref="OpenSim.Framework.IClientAPI.OnSetScriptRunning"/>,
345 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.HandleSetScriptRunning"/>
346 /// </remarks>
164 public event StartScript OnStartScript; 347 public event StartScript OnStartScript;
165 348
166 public delegate void StopScript(uint localID, UUID itemID); 349 public delegate void StopScript(uint localID, UUID itemID);
350
351 /// <summary>
352 /// Triggered when a script stops.
353 /// </summary>
354 /// <remarks>
355 /// Triggered by <see cref="TriggerStopScript"/>,
356 /// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>,
357 /// <see cref="SceneObjectPartInventory.StopScriptInstance"/>,
358 /// <see cref="Scene.SetScriptRunning"/>
359 /// </remarks>
167 public event StopScript OnStopScript; 360 public event StopScript OnStopScript;
168 361
169 public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta); 362 public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta);
363
364 /// <summary>
365 /// Triggered when an object is moved.
366 /// </summary>
367 /// <remarks>
368 /// Triggered by <see cref="TriggerGroupMove"/>
369 /// in <see cref="SceneObjectGroup.UpdateGroupPosition"/>,
370 /// <see cref="SceneObjectGroup.GrabMovement"/>
371 /// </remarks>
170 public event SceneGroupMoved OnSceneGroupMove; 372 public event SceneGroupMoved OnSceneGroupMove;
171 373
172 public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID); 374 public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID);
375
376 /// <summary>
377 /// Triggered when an object is grabbed.
378 /// </summary>
379 /// <remarks>
380 /// Triggered by <see cref="TriggerGroupGrab"/>
381 /// in <see cref="SceneObjectGroup.OnGrabGroup"/>
382 /// via <see cref="SceneObjectGroup.ObjectGrabHandler"/>
383 /// via <see cref="Scene.ProcessObjectGrab"/>
384 /// via <see cref="OpenSim.Framework.IClientAPI.OnGrabObject"/>
385 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectGrab"/>
386 /// </remarks>
173 public event SceneGroupGrabed OnSceneGroupGrab; 387 public event SceneGroupGrabed OnSceneGroupGrab;
174 388
175 public delegate bool SceneGroupSpinStarted(UUID groupID); 389 public delegate bool SceneGroupSpinStarted(UUID groupID);
390
391 /// <summary>
392 /// Triggered when an object starts to spin.
393 /// </summary>
394 /// <remarks>
395 /// Triggered by <see cref="TriggerGroupSpinStart"/>
396 /// in <see cref="SceneObjectGroup.SpinStart"/>
397 /// via <see cref="SceneGraph.SpinStart"/>
398 /// via <see cref="OpenSim.Framework.IClientAPI.OnSpinStart"/>
399 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectSpinStart"/>
400 /// </remarks>
176 public event SceneGroupSpinStarted OnSceneGroupSpinStart; 401 public event SceneGroupSpinStarted OnSceneGroupSpinStart;
177 402
178 public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation); 403 public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation);
404
405 /// <summary>
406 /// Triggered when an object is being spun.
407 /// </summary>
408 /// <remarks>
409 /// Triggered by <see cref="TriggerGroupSpin"/>
410 /// in <see cref="SceneObjectGroup.SpinMovement"/>
411 /// via <see cref="SceneGraph.SpinObject"/>
412 /// via <see cref="OpenSim.Framework.IClientAPI.OnSpinUpdate"/>
413 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectSpinUpdate"/>
414 /// </remarks>
179 public event SceneGroupSpun OnSceneGroupSpin; 415 public event SceneGroupSpun OnSceneGroupSpin;
180 416
181 public delegate void LandObjectAdded(ILandObject newParcel); 417 public delegate void LandObjectAdded(ILandObject newParcel);
@@ -204,6 +440,9 @@ namespace OpenSim.Region.Framework.Scenes
204 /// </summary> 440 /// </summary>
205 /// <remarks> 441 /// <remarks>
206 /// At the point of firing, the scene still contains the client's scene presence. 442 /// At the point of firing, the scene still contains the client's scene presence.
443 ///
444 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
445 /// do this on a separate thread.
207 /// </remarks> 446 /// </remarks>
208 public event ClientClosed OnClientClosed; 447 public event ClientClosed OnClientClosed;
209 448
@@ -214,6 +453,9 @@ namespace OpenSim.Region.Framework.Scenes
214 /// </summary> 453 /// </summary>
215 /// <remarks> 454 /// <remarks>
216 /// Occurs before OnRezScript 455 /// Occurs before OnRezScript
456 /// Triggered by <see cref="TriggerNewScript"/>
457 /// in <see cref="Scene.RezScriptFromAgentInventory"/>,
458 /// <see cref="Scene.RezNewScript"/>
217 /// </remarks> 459 /// </remarks>
218 public event NewScript OnNewScript; 460 public event NewScript OnNewScript;
219 461
@@ -248,6 +490,12 @@ namespace OpenSim.Region.Framework.Scenes
248 /// </summary> 490 /// </summary>
249 /// <remarks> 491 /// <remarks>
250 /// Triggered after the scene receives a client's upload of an updated script and has stored it in an asset. 492 /// Triggered after the scene receives a client's upload of an updated script and has stored it in an asset.
493 /// Triggered by <see cref="TriggerUpdateScript"/>
494 /// in <see cref="Scene.CapsUpdateTaskInventoryScriptAsset"/>
495 /// via <see cref="Scene.CapsUpdateTaskInventoryScriptAsset"/>
496 /// via <see cref="OpenSim.Region.ClientStack.Linden.BunchOfCaps.TaskScriptUpdated"/>
497 /// via <see cref="OpenSim.Region.ClientStack.Linden.TaskInventoryScriptUpdater.OnUpLoad"/>
498 /// via <see cref="OpenSim.Region.ClientStack.Linden.TaskInventoryScriptUpdater.uploaderCaps"/>
251 /// </remarks> 499 /// </remarks>
252 public event UpdateScript OnUpdateScript; 500 public event UpdateScript OnUpdateScript;
253 501
@@ -273,48 +521,203 @@ namespace OpenSim.Region.Framework.Scenes
273 } 521 }
274 522
275 /// <summary> 523 /// <summary>
524 /// Triggered when some scene object properties change.
525 /// </summary>
526 /// <remarks>
276 /// ScriptChangedEvent is fired when a scene object property that a script might be interested 527 /// ScriptChangedEvent is fired when a scene object property that a script might be interested
277 /// in (such as color, scale or inventory) changes. Only enough information sent is for the LSL changed event. 528 /// in (such as color, scale or inventory) changes. Only enough information sent is for the LSL changed event.
278 /// This is not an indication that the script has changed (see OnUpdateScript for that). 529 /// This is not an indication that the script has changed (see OnUpdateScript for that).
279 /// This event is sent to a script to tell it that some property changed on 530 /// This event is sent to a script to tell it that some property changed on
280 /// the object the script is in. See http://lslwiki.net/lslwiki/wakka.php?wakka=changed . 531 /// the object the script is in. See http://lslwiki.net/lslwiki/wakka.php?wakka=changed .
281 /// </summary> 532 /// Triggered by <see cref="TriggerOnScriptChangedEvent"/>
533 /// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.TeleportAgentWithinRegion"/>,
534 /// <see cref="SceneObjectPart.TriggerScriptChangedEvent"/>
535 /// </remarks>
282 public event ScriptChangedEvent OnScriptChangedEvent; 536 public event ScriptChangedEvent OnScriptChangedEvent;
283 public delegate void ScriptChangedEvent(uint localID, uint change); 537 public delegate void ScriptChangedEvent(uint localID, uint change);
284 538
285 public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed); 539 public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed);
540
541 /// <summary>
542 /// Triggered when a script receives control input from an agent.
543 /// </summary>
544 /// <remarks>
545 /// Triggered by <see cref="TriggerControlEvent"/>
546 /// in <see cref="ScenePresence.SendControlsToScripts"/>
547 /// via <see cref="ScenePresence.HandleAgentUpdate"/>
548 /// via <see cref="OpenSim.Framework.IClientAPI.OnAgentUpdate"/>
549 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleAgentUpdate"/>
550 /// </remarks>
286 public event ScriptControlEvent OnScriptControlEvent; 551 public event ScriptControlEvent OnScriptControlEvent;
287 552
288 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); 553 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
554
555 /// <summary>
556 /// Triggered when an object has arrived within a tolerance distance
557 /// of a motion target.
558 /// </summary>
559 /// <remarks>
560 /// Triggered by <see cref="TriggerAtTargetEvent"/>
561 /// in <see cref="SceneObjectGroup.checkAtTargets"/>
562 /// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
563 /// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
564 /// </remarks>
289 public event ScriptAtTargetEvent OnScriptAtTargetEvent; 565 public event ScriptAtTargetEvent OnScriptAtTargetEvent;
290 566
291 public delegate void ScriptNotAtTargetEvent(uint localID); 567 public delegate void ScriptNotAtTargetEvent(uint localID);
568
569 /// <summary>
570 /// Triggered when an object has a motion target but has not arrived
571 /// within a tolerance distance.
572 /// </summary>
573 /// <remarks>
574 /// Triggered by <see cref="TriggerNotAtTargetEvent"/>
575 /// in <see cref="SceneObjectGroup.checkAtTargets"/>
576 /// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
577 /// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
578 /// </remarks>
292 public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent; 579 public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent;
293 580
294 public delegate void ScriptAtRotTargetEvent(uint localID, uint handle, Quaternion targetrot, Quaternion atrot); 581 public delegate void ScriptAtRotTargetEvent(uint localID, uint handle, Quaternion targetrot, Quaternion atrot);
582
583 /// <summary>
584 /// Triggered when an object has arrived within a tolerance rotation
585 /// of a rotation target.
586 /// </summary>
587 /// <remarks>
588 /// Triggered by <see cref="TriggerAtRotTargetEvent"/>
589 /// in <see cref="SceneObjectGroup.checkAtTargets"/>
590 /// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
591 /// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
592 /// </remarks>
295 public event ScriptAtRotTargetEvent OnScriptAtRotTargetEvent; 593 public event ScriptAtRotTargetEvent OnScriptAtRotTargetEvent;
296 594
297 public delegate void ScriptNotAtRotTargetEvent(uint localID); 595 public delegate void ScriptNotAtRotTargetEvent(uint localID);
596
597 /// <summary>
598 /// Triggered when an object has a rotation target but has not arrived
599 /// within a tolerance rotation.
600 /// </summary>
601 /// <remarks>
602 /// Triggered by <see cref="TriggerNotAtRotTargetEvent"/>
603 /// in <see cref="SceneObjectGroup.checkAtTargets"/>
604 /// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
605 /// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
606 /// </remarks>
298 public event ScriptNotAtRotTargetEvent OnScriptNotAtRotTargetEvent; 607 public event ScriptNotAtRotTargetEvent OnScriptNotAtRotTargetEvent;
299 608
300 public delegate void ScriptColliding(uint localID, ColliderArgs colliders); 609 public delegate void ScriptColliding(uint localID, ColliderArgs colliders);
610
611 /// <summary>
612 /// Triggered when a physical collision has started between a prim
613 /// and something other than the region terrain.
614 /// </summary>
615 /// <remarks>
616 /// Triggered by <see cref="TriggerScriptCollidingStart"/>
617 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
618 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
619 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
620 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
621 /// </remarks>
301 public event ScriptColliding OnScriptColliderStart; 622 public event ScriptColliding OnScriptColliderStart;
623
624 /// <summary>
625 /// Triggered when something that previously collided with a prim has
626 /// not stopped colliding with it.
627 /// </summary>
628 /// <remarks>
629 /// <seealso cref="OnScriptColliderStart"/>
630 /// Triggered by <see cref="TriggerScriptColliding"/>
631 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
632 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
633 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
634 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
635 /// </remarks>
302 public event ScriptColliding OnScriptColliding; 636 public event ScriptColliding OnScriptColliding;
637
638 /// <summary>
639 /// Triggered when something that previously collided with a prim has
640 /// stopped colliding with it.
641 /// </summary>
642 /// <remarks>
643 /// Triggered by <see cref="TriggerScriptCollidingEnd"/>
644 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
645 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
646 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
647 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
648 /// </remarks>
303 public event ScriptColliding OnScriptCollidingEnd; 649 public event ScriptColliding OnScriptCollidingEnd;
650
651 /// <summary>
652 /// Triggered when a physical collision has started between an object
653 /// and the region terrain.
654 /// </summary>
655 /// <remarks>
656 /// Triggered by <see cref="TriggerScriptLandCollidingStart"/>
657 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
658 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
659 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
660 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
661 /// </remarks>
304 public event ScriptColliding OnScriptLandColliderStart; 662 public event ScriptColliding OnScriptLandColliderStart;
663
664 /// <summary>
665 /// Triggered when an object that previously collided with the region
666 /// terrain has not yet stopped colliding with it.
667 /// </summary>
668 /// <remarks>
669 /// Triggered by <see cref="TriggerScriptLandColliding"/>
670 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
671 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
672 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
673 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
674 /// </remarks>
305 public event ScriptColliding OnScriptLandColliding; 675 public event ScriptColliding OnScriptLandColliding;
676
677 /// <summary>
678 /// Triggered when an object that previously collided with the region
679 /// terrain has stopped colliding with it.
680 /// </summary>
681 /// <remarks>
682 /// Triggered by <see cref="TriggerScriptLandCollidingEnd"/>
683 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
684 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
685 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
686 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
687 /// </remarks>
306 public event ScriptColliding OnScriptLandColliderEnd; 688 public event ScriptColliding OnScriptLandColliderEnd;
307 689
308 public delegate void OnMakeChildAgentDelegate(ScenePresence presence); 690 public delegate void OnMakeChildAgentDelegate(ScenePresence presence);
691
692 /// <summary>
693 /// Triggered when an agent has been made a child agent of a scene.
694 /// </summary>
695 /// <remarks>
696 /// Triggered by <see cref="TriggerOnMakeChildAgent"/>
697 /// in <see cref="ScenePresence.MakeChildAgent"/>
698 /// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.CrossAgentToNewRegionAsync"/>,
699 /// <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>,
700 /// <see cref="OpenSim.Region.CoreModules.InterGrid.KillAUser.ShutdownNoLogout"/>
701 /// </remarks>
309 public event OnMakeChildAgentDelegate OnMakeChildAgent; 702 public event OnMakeChildAgentDelegate OnMakeChildAgent;
310 703
311 public delegate void OnSaveNewWindlightProfileDelegate(); 704 public delegate void OnSaveNewWindlightProfileDelegate();
312 public delegate void OnSendNewWindlightProfileTargetedDelegate(RegionLightShareData wl, UUID user); 705 public delegate void OnSendNewWindlightProfileTargetedDelegate(RegionLightShareData wl, UUID user);
313 706
314 /// <summary> 707 /// <summary>
708 /// Triggered after the grunt work for adding a root agent to a
709 /// scene has been performed (resuming attachment scripts, physics,
710 /// animations etc.)
711 /// </summary>
712 /// <remarks>
315 /// This event is on the critical path for transferring an avatar from one region to another. Try and do 713 /// This event is on the critical path for transferring an avatar from one region to another. Try and do
316 /// as little work on this event as possible, or do work asynchronously. 714 /// as little work on this event as possible, or do work asynchronously.
317 /// </summary> 715 /// Triggered after <see cref="OnSetRootAgentScene"/>
716 /// by <see cref="TriggerOnMakeRootAgent"/>
717 /// in <see cref="ScenePresence.MakeRootAgent"/>
718 /// via <see cref="Scene.AgentCrossing"/>
719 /// and <see cref="ScenePresence.CompleteMovement"/>
720 /// </remarks>
318 public event Action<ScenePresence> OnMakeRootAgent; 721 public event Action<ScenePresence> OnMakeRootAgent;
319 722
320 public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted; 723 public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted;
@@ -340,9 +743,17 @@ namespace OpenSim.Region.Framework.Scenes
340 public event AvatarKillData OnAvatarKilled; 743 public event AvatarKillData OnAvatarKilled;
341 public delegate void AvatarKillData(uint KillerLocalID, ScenePresence avatar); 744 public delegate void AvatarKillData(uint KillerLocalID, ScenePresence avatar);
342 745
343// public delegate void ScriptTimerEvent(uint localID, double timerinterval); 746 /*
344 747 public delegate void ScriptTimerEvent(uint localID, double timerinterval);
345// public event ScriptTimerEvent OnScriptTimerEvent; 748 /// <summary>
749 /// Used to be triggered when the LSL timer event fires.
750 /// </summary>
751 /// <remarks>
752 /// Triggered by <see cref="TriggerTimerEvent"/>
753 /// via <see cref="SceneObjectPart.handleTimerAccounting"/>
754 /// </remarks>
755 public event ScriptTimerEvent OnScriptTimerEvent;
756 */
346 757
347 public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); 758 public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour);
348 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); 759 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
@@ -352,12 +763,27 @@ namespace OpenSim.Region.Framework.Scenes
352 /// <summary> 763 /// <summary>
353 /// Triggered when an object is added to the scene. 764 /// Triggered when an object is added to the scene.
354 /// </summary> 765 /// </summary>
766 /// <remarks>
767 /// Triggered by <see cref="TriggerObjectAddedToScene"/>
768 /// in <see cref="Scene.AddNewSceneObject"/>,
769 /// <see cref="Scene.DuplicateObject"/>,
770 /// <see cref="Scene.doObjectDuplicateOnRay"/>
771 /// </remarks>
355 public event Action<SceneObjectGroup> OnObjectAddedToScene; 772 public event Action<SceneObjectGroup> OnObjectAddedToScene;
356 773
357 /// <summary> 774 /// <summary>
358 /// Triggered when an object is removed from the scene. 775 /// Delegate for <see cref="OnObjectBeingRemovedFromScene"/>
359 /// </summary> 776 /// </summary>
777 /// <param name="obj">The object being removed from the scene</param>
360 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); 778 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
779
780 /// <summary>
781 /// Triggered when an object is removed from the scene.
782 /// </summary>
783 /// <remarks>
784 /// Triggered by <see cref="TriggerObjectBeingRemovedFromScene"/>
785 /// in <see cref="Scene.DeleteSceneObject"/>
786 /// </remarks>
361 public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene; 787 public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene;
362 788
363 public delegate void NoticeNoLandDataFromStorage(); 789 public delegate void NoticeNoLandDataFromStorage();
@@ -373,6 +799,20 @@ namespace OpenSim.Region.Framework.Scenes
373 public event RequestParcelPrimCountUpdate OnRequestParcelPrimCountUpdate; 799 public event RequestParcelPrimCountUpdate OnRequestParcelPrimCountUpdate;
374 800
375 public delegate void ParcelPrimCountTainted(); 801 public delegate void ParcelPrimCountTainted();
802
803 /// <summary>
804 /// Triggered when the parcel prim count has been altered.
805 /// </summary>
806 /// <remarks>
807 /// Triggered by <see cref="TriggerParcelPrimCountTainted"/> in
808 /// <see cref="OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.DetachSingleAttachmentToGround"/>,
809 /// <see cref="OpenSim.Region.CoreModules.Avatar.Attachments.AttachmentsModule.AttachToAgent"/>,
810 /// <see cref="Scene.DeleteSceneObject"/>,
811 /// <see cref="Scene.SelectPrim"/>,
812 /// <see cref="Scene.DeselectPrim"/>,
813 /// <see cref="SceneObjectGroup.UpdatePrimFlags"/>,
814 /// <see cref="SceneObjectGroup.AbsolutePosition"/>
815 /// </remarks>
376 public event ParcelPrimCountTainted OnParcelPrimCountTainted; 816 public event ParcelPrimCountTainted OnParcelPrimCountTainted;
377 public event GetScriptRunning OnGetScriptRunning; 817 public event GetScriptRunning OnGetScriptRunning;
378 818
@@ -432,7 +872,7 @@ namespace OpenSim.Region.Framework.Scenes
432 /// the scripts may not have started yet 872 /// the scripts may not have started yet
433 /// Message is non empty string if there were problems loading the oar file 873 /// Message is non empty string if there were problems loading the oar file
434 /// </summary> 874 /// </summary>
435 public delegate void OarFileLoaded(Guid guid, string message); 875 public delegate void OarFileLoaded(Guid guid, List<UUID> loadedScenes, string message);
436 public event OarFileLoaded OnOarFileLoaded; 876 public event OarFileLoaded OnOarFileLoaded;
437 877
438 /// <summary> 878 /// <summary>
@@ -485,10 +925,13 @@ namespace OpenSim.Region.Framework.Scenes
485 /// <param name="copy"></param> 925 /// <param name="copy"></param>
486 /// <param name="original"></param> 926 /// <param name="original"></param>
487 /// <param name="userExposed">True if the duplicate will immediately be in the scene, false otherwise</param> 927 /// <param name="userExposed">True if the duplicate will immediately be in the scene, false otherwise</param>
928 /// <remarks>
929 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.SceneObjectPart.Copy"/>
930 /// </remarks>
488 public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy; 931 public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy;
489 public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed); 932 public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed);
490 933
491 public delegate void SceneObjectPartUpdated(SceneObjectPart sop); 934 public delegate void SceneObjectPartUpdated(SceneObjectPart sop, bool full);
492 public event SceneObjectPartUpdated OnSceneObjectPartUpdated; 935 public event SceneObjectPartUpdated OnSceneObjectPartUpdated;
493 936
494 public delegate void ScenePresenceUpdated(ScenePresence sp); 937 public delegate void ScenePresenceUpdated(ScenePresence sp);
@@ -526,9 +969,28 @@ namespace OpenSim.Region.Framework.Scenes
526 public event PrimsLoaded OnPrimsLoaded; 969 public event PrimsLoaded OnPrimsLoaded;
527 970
528 public delegate void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout); 971 public delegate void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout);
972
973 /// <summary>
974 /// Triggered when a teleport starts
975 /// </summary>
976 /// <remarks>
977 /// Triggered by <see cref="TriggerTeleportStart"/>
978 /// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.CreateAgent"/>
979 /// and <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.HGEntityTransferModule.CreateAgent"/>
980 /// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>
981 /// </remarks>
529 public event TeleportStart OnTeleportStart; 982 public event TeleportStart OnTeleportStart;
530 983
531 public delegate void TeleportFail(IClientAPI client, bool gridLogout); 984 public delegate void TeleportFail(IClientAPI client, bool gridLogout);
985
986 /// <summary>
987 /// Trigered when a teleport fails.
988 /// </summary>
989 /// <remarks>
990 /// Triggered by <see cref="TriggerTeleportFail"/>
991 /// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.Fail"/>
992 /// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>
993 /// </remarks>
532 public event TeleportFail OnTeleportFail; 994 public event TeleportFail OnTeleportFail;
533 995
534 public class MoneyTransferArgs : EventArgs 996 public class MoneyTransferArgs : EventArgs
@@ -536,7 +998,9 @@ namespace OpenSim.Region.Framework.Scenes
536 public UUID sender; 998 public UUID sender;
537 public UUID receiver; 999 public UUID receiver;
538 1000
539 // Always false. The SL protocol sucks. 1001 /// <summary>
1002 /// Always false. The SL protocol sucks.
1003 /// </summary>
540 public bool authenticated = false; 1004 public bool authenticated = false;
541 1005
542 public int amount; 1006 public int amount;
@@ -593,8 +1057,29 @@ namespace OpenSim.Region.Framework.Scenes
593 1057
594 public delegate void LandBuy(Object sender, LandBuyArgs e); 1058 public delegate void LandBuy(Object sender, LandBuyArgs e);
595 1059
1060 /// <summary>
1061 /// Triggered when an attempt to transfer grid currency occurs
1062 /// </summary>
1063 /// <remarks>
1064 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessMoneyTransferRequest"/>
1065 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientGridEvents"/>
1066 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientEvents"/>
1067 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/>
1068 /// </remarks>
596 public event MoneyTransferEvent OnMoneyTransfer; 1069 public event MoneyTransferEvent OnMoneyTransfer;
1070
1071 /// <summary>
1072 /// Triggered after after <see cref="OnValidateLandBuy"/>
1073 /// </summary>
597 public event LandBuy OnLandBuy; 1074 public event LandBuy OnLandBuy;
1075
1076 /// <summary>
1077 /// Triggered to allow or prevent a real estate transaction
1078 /// </summary>
1079 /// <remarks>
1080 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessParcelBuy"/>
1081 /// <seealso cref="OpenSim.Region.OptionalModules.World.MoneyModule.SampleMoneyModule.ValidateLandBuy"/>
1082 /// </remarks>
598 public event LandBuy OnValidateLandBuy; 1083 public event LandBuy OnValidateLandBuy;
599 1084
600 public void TriggerOnAttach(uint localID, UUID itemID, UUID avatarID) 1085 public void TriggerOnAttach(uint localID, UUID itemID, UUID avatarID)
@@ -2031,7 +2516,11 @@ namespace OpenSim.Region.Framework.Scenes
2031 } 2516 }
2032 } 2517 }
2033 2518
2034 // this lets us keep track of nasty script events like timer, etc. 2519 /// <summary>
2520 /// this lets us keep track of nasty script events like timer, etc.
2521 /// </summary>
2522 /// <param name="objLocalID"></param>
2523 /// <param name="Interval"></param>
2035 public void TriggerTimerEvent(uint objLocalID, double Interval) 2524 public void TriggerTimerEvent(uint objLocalID, double Interval)
2036 { 2525 {
2037 throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak"); 2526 throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak");
@@ -2093,7 +2582,7 @@ namespace OpenSim.Region.Framework.Scenes
2093 return 6; 2582 return 6;
2094 } 2583 }
2095 2584
2096 public void TriggerOarFileLoaded(Guid requestId, string message) 2585 public void TriggerOarFileLoaded(Guid requestId, List<UUID> loadedScenes, string message)
2097 { 2586 {
2098 OarFileLoaded handlerOarFileLoaded = OnOarFileLoaded; 2587 OarFileLoaded handlerOarFileLoaded = OnOarFileLoaded;
2099 if (handlerOarFileLoaded != null) 2588 if (handlerOarFileLoaded != null)
@@ -2102,7 +2591,7 @@ namespace OpenSim.Region.Framework.Scenes
2102 { 2591 {
2103 try 2592 try
2104 { 2593 {
2105 d(requestId, message); 2594 d(requestId, loadedScenes, message);
2106 } 2595 }
2107 catch (Exception e) 2596 catch (Exception e)
2108 { 2597 {
@@ -2387,7 +2876,7 @@ namespace OpenSim.Region.Framework.Scenes
2387 } 2876 }
2388 } 2877 }
2389 2878
2390 public void TriggerSceneObjectPartUpdated(SceneObjectPart sop) 2879 public void TriggerSceneObjectPartUpdated(SceneObjectPart sop, bool full)
2391 { 2880 {
2392 SceneObjectPartUpdated handler = OnSceneObjectPartUpdated; 2881 SceneObjectPartUpdated handler = OnSceneObjectPartUpdated;
2393 if (handler != null) 2882 if (handler != null)
@@ -2396,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
2396 { 2885 {
2397 try 2886 try
2398 { 2887 {
2399 d(sop); 2888 d(sop, full);
2400 } 2889 }
2401 catch (Exception e) 2890 catch (Exception e)
2402 { 2891 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index ff8589a..deb57ce 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -93,7 +93,7 @@ namespace OpenSim.Region.Framework.Scenes
93 /// </summary> 93 /// </summary>
94 public void StartScripts() 94 public void StartScripts()
95 { 95 {
96 m_log.InfoFormat("[SCENE]: Starting scripts in {0}, please wait.", RegionInfo.RegionName); 96// m_log.InfoFormat("[SCENE]: Starting scripts in {0}, please wait.", RegionInfo.RegionName);
97 97
98 IScriptModule[] engines = RequestModuleInterfaces<IScriptModule>(); 98 IScriptModule[] engines = RequestModuleInterfaces<IScriptModule>();
99 99
@@ -1469,7 +1469,7 @@ namespace OpenSim.Region.Framework.Scenes
1469 return newFolderID; 1469 return newFolderID;
1470 } 1470 }
1471 1471
1472 private void SendInventoryUpdate(IClientAPI client, InventoryFolderBase folder, bool fetchFolders, bool fetchItems) 1472 public void SendInventoryUpdate(IClientAPI client, InventoryFolderBase folder, bool fetchFolders, bool fetchItems)
1473 { 1473 {
1474 if (folder == null) 1474 if (folder == null)
1475 return; 1475 return;
@@ -1997,6 +1997,9 @@ namespace OpenSim.Region.Framework.Scenes
1997 // If child prims have invalid perms, fix them 1997 // If child prims have invalid perms, fix them
1998 grp.AdjustChildPrimPermissions(); 1998 grp.AdjustChildPrimPermissions();
1999 1999
2000 // If child prims have invalid perms, fix them
2001 grp.AdjustChildPrimPermissions();
2002
2000 if (remoteClient == null) 2003 if (remoteClient == null)
2001 { 2004 {
2002 // Autoreturn has a null client. Nothing else does. So 2005 // Autoreturn has a null client. Nothing else does. So
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index e970543..16c0d25 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -543,7 +543,7 @@ namespace OpenSim.Region.Framework.Scenes
543 if (!InventoryService.AddFolder(folder)) 543 if (!InventoryService.AddFolder(folder))
544 { 544 {
545 m_log.WarnFormat( 545 m_log.WarnFormat(
546 "[AGENT INVENTORY]: Failed to move create folder for user {0} {1}", 546 "[AGENT INVENTORY]: Failed to create folder for user {0} {1}",
547 remoteClient.Name, remoteClient.AgentId); 547 remoteClient.Name, remoteClient.AgentId);
548 } 548 }
549 } 549 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 8034bc6..45d512b 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -80,6 +80,11 @@ namespace OpenSim.Region.Framework.Scenes
80 public SynchronizeSceneHandler SynchronizeScene; 80 public SynchronizeSceneHandler SynchronizeScene;
81 81
82 /// <summary> 82 /// <summary>
83 /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
84 /// </summary>
85 private object m_removeClientLock = new object();
86
87 /// <summary>
83 /// Statistical information for this scene. 88 /// Statistical information for this scene.
84 /// </summary> 89 /// </summary>
85 public SimStatsReporter StatsReporter { get; private set; } 90 public SimStatsReporter StatsReporter { get; private set; }
@@ -103,8 +108,31 @@ namespace OpenSim.Region.Framework.Scenes
103 /// </summary> 108 /// </summary>
104 public bool CollidablePrims { get; private set; } 109 public bool CollidablePrims { get; private set; }
105 110
111 /// <summary>
112 /// Minimum value of the size of a non-physical prim in each axis
113 /// </summary>
114 public float m_minNonphys = 0.001f;
115
116 /// <summary>
117 /// Maximum value of the size of a non-physical prim in each axis
118 /// </summary>
106 public float m_maxNonphys = 256; 119 public float m_maxNonphys = 256;
120
121 /// <summary>
122 /// Minimum value of the size of a physical prim in each axis
123 /// </summary>
124 public float m_minPhys = 0.01f;
125
126 /// <summary>
127 /// Maximum value of the size of a physical prim in each axis
128 /// </summary>
107 public float m_maxPhys = 10; 129 public float m_maxPhys = 10;
130
131 /// <summary>
132 /// Max prims an object will hold
133 /// </summary>
134 public int m_linksetCapacity = 0;
135
108 public bool m_clampPrimSize; 136 public bool m_clampPrimSize;
109 public bool m_trustBinaries; 137 public bool m_trustBinaries;
110 public bool m_allowScriptCrossings; 138 public bool m_allowScriptCrossings;
@@ -285,6 +313,31 @@ namespace OpenSim.Region.Framework.Scenes
285 } 313 }
286 private volatile bool m_shuttingDown; 314 private volatile bool m_shuttingDown;
287 315
316 /// <summary>
317 /// Is the scene active?
318 /// </summary>
319 /// <remarks>
320 /// If false, maintenance and update loops are not being run. Updates can still be triggered manually if
321 /// the scene is not active.
322 /// </remarks>
323 public bool Active
324 {
325 get { return m_active; }
326 set
327 {
328 if (value)
329 {
330 if (!m_active)
331 Start();
332 }
333 else
334 {
335 m_active = false;
336 }
337 }
338 }
339 private volatile bool m_active;
340
288// private int m_lastUpdate; 341// private int m_lastUpdate;
289 private bool m_firstHeartbeat = true; 342 private bool m_firstHeartbeat = true;
290 343
@@ -746,12 +799,24 @@ namespace OpenSim.Region.Framework.Scenes
746 PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); 799 PhysicalPrims = startupConfig.GetBoolean("physical_prim", true);
747 CollidablePrims = startupConfig.GetBoolean("collidable_prim", true); 800 CollidablePrims = startupConfig.GetBoolean("collidable_prim", true);
748 801
749 m_maxNonphys = startupConfig.GetFloat("NonphysicalPrimMax", m_maxNonphys); 802 m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys);
803 if (RegionInfo.NonphysPrimMin > 0)
804 {
805 m_minNonphys = RegionInfo.NonphysPrimMin;
806 }
807
808 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
750 if (RegionInfo.NonphysPrimMax > 0) 809 if (RegionInfo.NonphysPrimMax > 0)
751 { 810 {
752 m_maxNonphys = RegionInfo.NonphysPrimMax; 811 m_maxNonphys = RegionInfo.NonphysPrimMax;
753 } 812 }
754 813
814 m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys);
815 if (RegionInfo.PhysPrimMin > 0)
816 {
817 m_minPhys = RegionInfo.PhysPrimMin;
818 }
819
755 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys); 820 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
756 821
757 if (RegionInfo.PhysPrimMax > 0) 822 if (RegionInfo.PhysPrimMax > 0)
@@ -759,6 +824,12 @@ namespace OpenSim.Region.Framework.Scenes
759 m_maxPhys = RegionInfo.PhysPrimMax; 824 m_maxPhys = RegionInfo.PhysPrimMax;
760 } 825 }
761 826
827 m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity);
828 if (RegionInfo.LinksetCapacity > 0)
829 {
830 m_linksetCapacity = RegionInfo.LinksetCapacity;
831 }
832
762 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); 833 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest");
763 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); 834 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false);
764 835
@@ -784,13 +855,6 @@ namespace OpenSim.Region.Framework.Scenes
784 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 855 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
785 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine); 856 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
786 857
787 IConfig packetConfig = m_config.Configs["PacketPool"];
788 if (packetConfig != null)
789 {
790 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
791 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
792 }
793
794 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 858 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
795 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion); 859 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
796 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false); 860 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
@@ -854,6 +918,8 @@ namespace OpenSim.Region.Framework.Scenes
854 } 918 }
855 919
856 // FIXME: Ultimately this should be in a module. 920 // FIXME: Ultimately this should be in a module.
921 SendPeriodicAppearanceUpdates = true;
922
857 IConfig appearanceConfig = m_config.Configs["Appearance"]; 923 IConfig appearanceConfig = m_config.Configs["Appearance"];
858 if (appearanceConfig != null) 924 if (appearanceConfig != null)
859 { 925 {
@@ -1151,6 +1217,14 @@ namespace OpenSim.Region.Framework.Scenes
1151 1217
1152 public void SetSceneCoreDebug(Dictionary<string, string> options) 1218 public void SetSceneCoreDebug(Dictionary<string, string> options)
1153 { 1219 {
1220 if (options.ContainsKey("active"))
1221 {
1222 bool active;
1223
1224 if (bool.TryParse(options["active"], out active))
1225 Active = active;
1226 }
1227
1154 if (options.ContainsKey("scripting")) 1228 if (options.ContainsKey("scripting"))
1155 { 1229 {
1156 bool enableScripts = true; 1230 bool enableScripts = true;
@@ -1290,6 +1364,8 @@ namespace OpenSim.Region.Framework.Scenes
1290 /// </summary> 1364 /// </summary>
1291 public void Start() 1365 public void Start()
1292 { 1366 {
1367 m_active = true;
1368
1293// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); 1369// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
1294 1370
1295 //m_heartbeatTimer.Enabled = true; 1371 //m_heartbeatTimer.Enabled = true;
@@ -1346,7 +1422,7 @@ namespace OpenSim.Region.Framework.Scenes
1346 #region Update Methods 1422 #region Update Methods
1347 1423
1348 /// <summary> 1424 /// <summary>
1349 /// Performs per-frame updates regularly 1425 /// Activate the various loops necessary to continually update the scene.
1350 /// </summary> 1426 /// </summary>
1351 private void Heartbeat() 1427 private void Heartbeat()
1352 { 1428 {
@@ -1403,7 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes
1403 List<Vector3> coarseLocations; 1479 List<Vector3> coarseLocations;
1404 List<UUID> avatarUUIDs; 1480 List<UUID> avatarUUIDs;
1405 1481
1406 while (!m_shuttingDown && (endRun == null || MaintenanceRun < endRun)) 1482 while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun))
1407 { 1483 {
1408 runtc = Util.EnvironmentTickCount(); 1484 runtc = Util.EnvironmentTickCount();
1409 ++MaintenanceRun; 1485 ++MaintenanceRun;
@@ -1465,7 +1541,7 @@ namespace OpenSim.Region.Framework.Scenes
1465 int sleepMS; 1541 int sleepMS;
1466 int framestart; 1542 int framestart;
1467 1543
1468 while (!m_shuttingDown && (endFrame == null || Frame < endFrame)) 1544 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
1469 { 1545 {
1470 framestart = Util.EnvironmentTickCount(); 1546 framestart = Util.EnvironmentTickCount();
1471 ++Frame; 1547 ++Frame;
@@ -2182,10 +2258,14 @@ namespace OpenSim.Region.Framework.Scenes
2182 public bool AddRestoredSceneObject( 2258 public bool AddRestoredSceneObject(
2183 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 2259 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
2184 { 2260 {
2185 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 2261 if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates))
2186 if (result) 2262 {
2187 sceneObject.IsDeleted = false; 2263 sceneObject.IsDeleted = false;
2188 return result; 2264 EventManager.TriggerObjectAddedToScene(sceneObject);
2265 return true;
2266 }
2267
2268 return false;
2189 } 2269 }
2190 2270
2191 /// <summary> 2271 /// <summary>
@@ -2826,77 +2906,89 @@ namespace OpenSim.Region.Framework.Scenes
2826 2906
2827 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 2907 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
2828 { 2908 {
2909 ScenePresence sp;
2910 bool vialogin;
2911
2829 // Validation occurs in LLUDPServer 2912 // Validation occurs in LLUDPServer
2913 //
2914 // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
2915 // each other. In practice, this does not currently occur in the code.
2830 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); 2916 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2831 2917
2832 bool vialogin 2918 // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
2833 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 2919 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2834 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2920 // whilst connecting).
2835 2921 //
2836 CheckHeartbeat(); 2922 // It would be easier to lock across all NewUserConnection(), AddNewClient() and
2837 2923 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2838 ScenePresence sp = GetScenePresence(client.AgentId); 2924 // response in some module listening to AddNewClient()) from holding up unrelated agent calls.
2839 2925 //
2840 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this 2926 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2841 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause 2927 // AddNewClient() operations (though not other ops).
2842 // other problems, and possible the code calling AddNewClient() should ensure that no client is already 2928 // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
2843 // connected. 2929 lock (aCircuit)
2844 if (sp == null) 2930 {
2845 { 2931 vialogin
2846 m_log.DebugFormat( 2932 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2847 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", 2933 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2848 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); 2934
2849 2935 CheckHeartbeat();
2850 m_clientManager.Add(client); 2936
2851 SubscribeToClientEvents(client); 2937 sp = GetScenePresence(client.AgentId);
2852
2853 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2854 m_eventManager.TriggerOnNewPresence(sp);
2855
2856 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2857 2938
2858 // The first agent upon login is a root agent by design. 2939 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2859 // For this agent we will have to rez the attachments. 2940 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2860 // All other AddNewClient calls find aCircuit.child to be true. 2941 // other problems, and possible the code calling AddNewClient() should ensure that no client is already
2861 if (aCircuit.child == false) 2942 // connected.
2943 if (sp == null)
2862 { 2944 {
2863 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to 2945 m_log.DebugFormat(
2864 // start the scripts again (since this is done in RezAttachments()). 2946 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2865 // XXX: This is convoluted. 2947 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2866 sp.IsChildAgent = false; 2948
2867 2949 m_clientManager.Add(client);
2868 if (AttachmentsModule != null) 2950 SubscribeToClientEvents(client);
2869 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); 2951
2952 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2953 m_eventManager.TriggerOnNewPresence(sp);
2954
2955 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2956
2957 // The first agent upon login is a root agent by design.
2958 // For this agent we will have to rez the attachments.
2959 // All other AddNewClient calls find aCircuit.child to be true.
2960 if (aCircuit.child == false)
2961 {
2962 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
2963 // start the scripts again (since this is done in RezAttachments()).
2964 // XXX: This is convoluted.
2965 sp.IsChildAgent = false;
2966
2967 if (AttachmentsModule != null)
2968 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
2969 }
2870 } 2970 }
2871 } 2971 else
2872 else 2972 {
2873 { 2973 m_log.WarnFormat(
2874 m_log.WarnFormat( 2974 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2875 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", 2975 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
2876 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); 2976 }
2877 } 2977
2978 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2979 // client is for a root or child agent.
2980 client.SceneAgent = sp;
2878 2981
2879 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the 2982 // Cache the user's name
2880 // client is for a root or child agent. 2983 CacheUserName(sp, aCircuit);
2881 client.SceneAgent = sp; 2984
2985 EventManager.TriggerOnNewClient(client);
2986 if (vialogin)
2987 EventManager.TriggerOnClientLogin(client);
2988 }
2882 2989
2883 m_LastLogin = Util.EnvironmentTickCount(); 2990 m_LastLogin = Util.EnvironmentTickCount();
2884 2991
2885 // Cache the user's name
2886 CacheUserName(sp, aCircuit);
2887
2888 EventManager.TriggerOnNewClient(client);
2889 if (vialogin)
2890 {
2891 EventManager.TriggerOnClientLogin(client);
2892 // Send initial parcel data
2893/* this is done on TriggerOnNewClient by landmanegement respective event handler
2894 Vector3 pos = sp.AbsolutePosition;
2895 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2896 land.SendLandUpdateToClient(client);
2897*/
2898 }
2899
2900 return sp; 2992 return sp;
2901 } 2993 }
2902 2994
@@ -3436,110 +3528,130 @@ namespace OpenSim.Region.Framework.Scenes
3436 { 3528 {
3437// CheckHeartbeat(); 3529// CheckHeartbeat();
3438 bool isChildAgent = false; 3530 bool isChildAgent = false;
3439 ScenePresence avatar = GetScenePresence(agentID); 3531 AgentCircuitData acd;
3440
3441 if (avatar == null)
3442 {
3443 m_log.WarnFormat(
3444 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3445
3446 return;
3447 }
3448 3532
3449 try 3533 lock (m_removeClientLock)
3450 { 3534 {
3451 isChildAgent = avatar.IsChildAgent; 3535 acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3452
3453 m_log.DebugFormat(
3454 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3455 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3456 3536
3457 // Don't do this to root agents, it's not nice for the viewer 3537 if (acd == null)
3458 if (closeChildAgents && isChildAgent)
3459 { 3538 {
3460 // Tell a single agent to disconnect from the region. 3539 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
3461 IEventQueue eq = RequestModuleInterface<IEventQueue>(); 3540 return;
3462 if (eq != null)
3463 {
3464 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3465 }
3466 else
3467 {
3468 avatar.ControllingClient.SendShutdownConnectionNotice();
3469 }
3470 } 3541 }
3471 3542 else
3472 // Only applies to root agents.
3473 if (avatar.ParentID != 0)
3474 { 3543 {
3475 avatar.StandUp(); 3544 // We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred
3545 // simultaneously.
3546 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3476 } 3547 }
3548 }
3477 3549
3478 m_sceneGraph.removeUserCount(!isChildAgent); 3550 lock (acd)
3479 3551 {
3480 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop 3552 ScenePresence avatar = GetScenePresence(agentID);
3481 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI 3553
3482 if (closeChildAgents && CapsModule != null) 3554 if (avatar == null)
3483 CapsModule.RemoveCaps(agentID);
3484
3485 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3486 // this method is doing is HORRIBLE!!!
3487 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3488
3489 if (closeChildAgents && !isChildAgent)
3490 { 3555 {
3491 List<ulong> regions = avatar.KnownRegionHandles; 3556 m_log.WarnFormat(
3492 regions.Remove(RegionInfo.RegionHandle); 3557 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3493 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3558
3559 return;
3494 } 3560 }
3495 3561
3496 m_eventManager.TriggerClientClosed(agentID, this); 3562 try
3497 m_eventManager.TriggerOnRemovePresence(agentID);
3498
3499 if (!isChildAgent)
3500 { 3563 {
3501 if (AttachmentsModule != null) 3564 isChildAgent = avatar.IsChildAgent;
3565
3566 m_log.DebugFormat(
3567 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3568 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3569
3570 // Don't do this to root agents, it's not nice for the viewer
3571 if (closeChildAgents && isChildAgent)
3502 { 3572 {
3503 AttachmentsModule.DeRezAttachments(avatar); 3573 // Tell a single agent to disconnect from the region.
3574 IEventQueue eq = RequestModuleInterface<IEventQueue>();
3575 if (eq != null)
3576 {
3577 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3578 }
3579 else
3580 {
3581 avatar.ControllingClient.SendShutdownConnectionNotice();
3582 }
3504 } 3583 }
3505 3584
3506 ForEachClient( 3585 // Only applies to root agents.
3507 delegate(IClientAPI client) 3586 if (avatar.ParentID != 0)
3587 {
3588 avatar.StandUp();
3589 }
3590
3591 m_sceneGraph.removeUserCount(!isChildAgent);
3592
3593 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3594 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3595 if (closeChildAgents && CapsModule != null)
3596 CapsModule.RemoveCaps(agentID);
3597
3598 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3599 // this method is doing is HORRIBLE!!!
3600 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3601
3602 if (closeChildAgents && !isChildAgent)
3603 {
3604 List<ulong> regions = avatar.KnownRegionHandles;
3605 regions.Remove(RegionInfo.RegionHandle);
3606 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3607 }
3608
3609 m_eventManager.TriggerClientClosed(agentID, this);
3610 m_eventManager.TriggerOnRemovePresence(agentID);
3611
3612 if (!isChildAgent)
3613 {
3614 if (AttachmentsModule != null)
3508 { 3615 {
3509 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3616 AttachmentsModule.DeRezAttachments(avatar);
3510 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } 3617 }
3511 catch (NullReferenceException) { }
3512 });
3513 }
3514
3515 // It's possible for child agents to have transactions if changes are being made cross-border.
3516 if (AgentTransactionsModule != null)
3517 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3518 3618
3519 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3619 ForEachClient(
3520 m_log.Debug("[Scene] The avatar has left the building"); 3620 delegate(IClientAPI client)
3521 } 3621 {
3522 catch (Exception e) 3622 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3523 { 3623 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); }
3524 m_log.Error( 3624 catch (NullReferenceException) { }
3525 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e); 3625 });
3526 } 3626 }
3527 finally
3528 {
3529 try
3530 {
3531 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3532 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3533 // the same cleanup exception continually.
3534 m_sceneGraph.RemoveScenePresence(agentID);
3535 m_clientManager.Remove(agentID);
3536 3627
3537 avatar.Close(); 3628 // It's possible for child agents to have transactions if changes are being made cross-border.
3629 if (AgentTransactionsModule != null)
3630 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3631 m_log.Debug("[Scene] The avatar has left the building");
3538 } 3632 }
3539 catch (Exception e) 3633 catch (Exception e)
3540 { 3634 {
3541 m_log.Error( 3635 m_log.Error(
3542 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); 3636 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3637 }
3638 finally
3639 {
3640 try
3641 {
3642 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3643 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3644 // the same cleanup exception continually.
3645 m_sceneGraph.RemoveScenePresence(agentID);
3646 m_clientManager.Remove(agentID);
3647
3648 avatar.Close();
3649 }
3650 catch (Exception e)
3651 {
3652 m_log.Error(
3653 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3654 }
3543 } 3655 }
3544 } 3656 }
3545 3657
@@ -3598,11 +3710,9 @@ namespace OpenSim.Region.Framework.Scenes
3598 3710
3599 /// <summary> 3711 /// <summary>
3600 /// Do the work necessary to initiate a new user connection for a particular scene. 3712 /// Do the work necessary to initiate a new user connection for a particular scene.
3601 /// At the moment, this consists of setting up the caps infrastructure
3602 /// The return bool should allow for connections to be refused, but as not all calling paths
3603 /// take proper notice of it let, we allowed banned users in still.
3604 /// </summary> 3713 /// </summary>
3605 /// <param name="agent">CircuitData of the agent who is connecting</param> 3714 /// <param name="agent">CircuitData of the agent who is connecting</param>
3715 /// <param name="teleportFlags"></param>
3606 /// <param name="reason">Outputs the reason for the false response on this string</param> 3716 /// <param name="reason">Outputs the reason for the false response on this string</param>
3607 /// <returns>True if the region accepts this agent. False if it does not. False will 3717 /// <returns>True if the region accepts this agent. False if it does not. False will
3608 /// also return a reason.</returns> 3718 /// also return a reason.</returns>
@@ -3613,10 +3723,20 @@ namespace OpenSim.Region.Framework.Scenes
3613 3723
3614 /// <summary> 3724 /// <summary>
3615 /// Do the work necessary to initiate a new user connection for a particular scene. 3725 /// Do the work necessary to initiate a new user connection for a particular scene.
3616 /// At the moment, this consists of setting up the caps infrastructure 3726 /// </summary>
3727 /// <remarks>
3728 /// The return bool should allow for connections to be refused, but as not all calling paths
3729 /// take proper notice of it yet, we still allowed banned users in.
3730 ///
3731 /// At the moment this method consists of setting up the caps infrastructure
3617 /// The return bool should allow for connections to be refused, but as not all calling paths 3732 /// The return bool should allow for connections to be refused, but as not all calling paths
3618 /// take proper notice of it let, we allowed banned users in still. 3733 /// take proper notice of it let, we allowed banned users in still.
3619 /// </summary> 3734 ///
3735 /// This method is called by the login service (in the case of login) or another simulator (in the case of region
3736 /// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
3737 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3738 /// the LLUDP stack).
3739 /// </remarks>
3620 /// <param name="agent">CircuitData of the agent who is connecting</param> 3740 /// <param name="agent">CircuitData of the agent who is connecting</param>
3621 /// <param name="reason">Outputs the reason for the false response on this string</param> 3741 /// <param name="reason">Outputs the reason for the false response on this string</param>
3622 /// <param name="requirePresenceLookup">True for normal presence. False for NPC 3742 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
@@ -3715,83 +3835,86 @@ namespace OpenSim.Region.Framework.Scenes
3715 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", 3835 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3716 sp.Name, sp.UUID, RegionInfo.RegionName); 3836 sp.Name, sp.UUID, RegionInfo.RegionName);
3717 3837
3718 sp.ControllingClient.Close(); 3838 sp.ControllingClient.Close(true, true);
3719 sp = null; 3839 sp = null;
3720 } 3840 }
3721 3841
3722 3842 lock (agent)
3723 //On login test land permisions
3724 if (vialogin)
3725 { 3843 {
3726 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); 3844 //On login test land permisions
3727 if (cache != null) 3845 if (vialogin)
3728 cache.Remove(agent.firstname + " " + agent.lastname);
3729 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3730 { 3846 {
3731 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); 3847 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3732 return false; 3848 if (cache != null)
3849 cache.Remove(agent.firstname + " " + agent.lastname);
3850 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3851 {
3852 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3853 return false;
3854 }
3733 } 3855 }
3734 }
3735 3856
3736 if (sp == null) // We don't have an [child] agent here already 3857 if (sp == null) // We don't have an [child] agent here already
3737 {
3738 if (requirePresenceLookup)
3739 { 3858 {
3740 try 3859 if (requirePresenceLookup)
3741 { 3860 {
3742 if (!VerifyUserPresence(agent, out reason)) 3861 try
3862 {
3863 if (!VerifyUserPresence(agent, out reason))
3864 return false;
3865 } catch (Exception e)
3866 {
3867 m_log.ErrorFormat(
3868 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3743 return false; 3869 return false;
3744 } catch (Exception e) 3870 }
3871 }
3872
3873 try
3874 {
3875 // Always check estate if this is a login. Always
3876 // check if banned regions are to be blacked out.
3877 if (vialogin || (!m_seeIntoBannedRegion))
3878 {
3879 if (!AuthorizeUser(agent, out reason))
3880 return false;
3881 }
3882 }
3883 catch (Exception e)
3745 { 3884 {
3746 m_log.ErrorFormat( 3885 m_log.ErrorFormat(
3747 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3886 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3748 return false; 3887 return false;
3749 } 3888 }
3750 }
3751 3889
3752 try 3890 m_log.InfoFormat(
3753 { 3891 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3754 // Always check estate if this is a login. Always 3892 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3755 // check if banned regions are to be blacked out. 3893 agent.AgentID, agent.circuitcode);
3756 if (vialogin || (!m_seeIntoBannedRegion)) 3894
3895 if (CapsModule != null)
3757 { 3896 {
3758 if (!AuthorizeUser(agent, out reason)) 3897 CapsModule.SetAgentCapsSeeds(agent);
3759 return false; 3898 CapsModule.CreateCaps(agent.AgentID);
3760 } 3899 }
3761 } 3900 }
3762 catch (Exception e) 3901 else
3763 { 3902 {
3764 m_log.ErrorFormat( 3903 // Let the SP know how we got here. This has a lot of interesting
3765 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 3904 // uses down the line.
3766 return false; 3905 sp.TeleportFlags = (TPFlags)teleportFlags;
3767 }
3768
3769 m_log.InfoFormat(
3770 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3771 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3772 agent.AgentID, agent.circuitcode);
3773 3906
3774 if (CapsModule != null) 3907 if (sp.IsChildAgent)
3775 { 3908 {
3776 CapsModule.SetAgentCapsSeeds(agent); 3909 m_log.DebugFormat(
3777 CapsModule.CreateCaps(agent.AgentID); 3910 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3778 } 3911 agent.AgentID, RegionInfo.RegionName);
3779 } else
3780 {
3781 // Let the SP know how we got here. This has a lot of interesting
3782 // uses down the line.
3783 sp.TeleportFlags = (TPFlags)teleportFlags;
3784 3912
3785 if (sp.IsChildAgent) 3913 sp.AdjustKnownSeeds();
3786 {
3787 m_log.DebugFormat(
3788 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3789 agent.AgentID, RegionInfo.RegionName);
3790 3914
3791 sp.AdjustKnownSeeds(); 3915 if (CapsModule != null)
3792 3916 CapsModule.SetAgentCapsSeeds(agent);
3793 if (CapsModule != null) 3917 }
3794 CapsModule.SetAgentCapsSeeds(agent);
3795 } 3918 }
3796 } 3919 }
3797 3920
@@ -4222,8 +4345,9 @@ namespace OpenSim.Region.Framework.Scenes
4222 return false; 4345 return false;
4223 } 4346 }
4224 4347
4225 // We have to wait until the viewer contacts this region after receiving EAC. 4348 // We have to wait until the viewer contacts this region
4226 // That calls AddNewClient, which finally creates the ScenePresence 4349 // after receiving the EnableSimulator HTTP Event Queue message. This triggers the viewer to send
4350 // a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence.
4227 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); 4351 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
4228 4352
4229 if (childAgentUpdate != null) 4353 if (childAgentUpdate != null)
@@ -4318,15 +4442,18 @@ namespace OpenSim.Region.Framework.Scenes
4318 /// Tell a single agent to disconnect from the region. 4442 /// Tell a single agent to disconnect from the region.
4319 /// </summary> 4443 /// </summary>
4320 /// <param name="agentID"></param> 4444 /// <param name="agentID"></param>
4321 /// <param name="childOnly"></param> 4445 /// <param name="force">
4322 public bool IncomingCloseAgent(UUID agentID, bool childOnly) 4446 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
4447 /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
4448 /// </param>
4449 public bool IncomingCloseAgent(UUID agentID, bool force)
4323 { 4450 {
4324 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 4451 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
4325 4452
4326 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); 4453 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
4327 if (presence != null) 4454 if (presence != null)
4328 { 4455 {
4329 presence.ControllingClient.Close(false); 4456 presence.ControllingClient.Close(force, force);
4330 return true; 4457 return true;
4331 } 4458 }
4332 4459
@@ -4532,6 +4659,16 @@ namespace OpenSim.Region.Framework.Scenes
4532 return LandChannel.GetLandObject(x, y).LandData; 4659 return LandChannel.GetLandObject(x, y).LandData;
4533 } 4660 }
4534 4661
4662 /// <summary>
4663 /// Get LandData by position.
4664 /// </summary>
4665 /// <param name="pos"></param>
4666 /// <returns></returns>
4667 public LandData GetLandData(Vector3 pos)
4668 {
4669 return GetLandData(pos.X, pos.Y);
4670 }
4671
4535 public LandData GetLandData(uint x, uint y) 4672 public LandData GetLandData(uint x, uint y)
4536 { 4673 {
4537 m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y); 4674 m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y);
@@ -4780,6 +4917,18 @@ namespace OpenSim.Region.Framework.Scenes
4780 } 4917 }
4781 4918
4782 /// <summary> 4919 /// <summary>
4920 /// Attempt to get the SOG via its UUID
4921 /// </summary>
4922 /// <param name="fullID"></param>
4923 /// <param name="sog"></param>
4924 /// <returns></returns>
4925 public bool TryGetSceneObjectGroup(UUID fullID, out SceneObjectGroup sog)
4926 {
4927 sog = GetSceneObjectGroup(fullID);
4928 return sog != null;
4929 }
4930
4931 /// <summary>
4783 /// Get a prim by name from the scene (will return the first 4932 /// Get a prim by name from the scene (will return the first
4784 /// found, if there are more than one prim with the same name) 4933 /// found, if there are more than one prim with the same name)
4785 /// </summary> 4934 /// </summary>
@@ -4811,6 +4960,18 @@ namespace OpenSim.Region.Framework.Scenes
4811 } 4960 }
4812 4961
4813 /// <summary> 4962 /// <summary>
4963 /// Attempt to get a prim via its UUID
4964 /// </summary>
4965 /// <param name="fullID"></param>
4966 /// <param name="sop"></param>
4967 /// <returns></returns>
4968 public bool TryGetSceneObjectPart(UUID fullID, out SceneObjectPart sop)
4969 {
4970 sop = GetSceneObjectPart(fullID);
4971 return sop != null;
4972 }
4973
4974 /// <summary>
4814 /// Get a scene object group that contains the prim with the given local id 4975 /// Get a scene object group that contains the prim with the given local id
4815 /// </summary> 4976 /// </summary>
4816 /// <param name="localID"></param> 4977 /// <param name="localID"></param>
@@ -5865,6 +6026,9 @@ Environment.Exit(1);
5865 6026
5866 public string GetExtraSetting(string name) 6027 public string GetExtraSetting(string name)
5867 { 6028 {
6029 if (m_extraSettings == null)
6030 return String.Empty;
6031
5868 string val; 6032 string val;
5869 6033
5870 if (!m_extraSettings.TryGetValue(name, out val)) 6034 if (!m_extraSettings.TryGetValue(name, out val))
@@ -5875,6 +6039,9 @@ Environment.Exit(1);
5875 6039
5876 public void StoreExtraSetting(string name, string val) 6040 public void StoreExtraSetting(string name, string val)
5877 { 6041 {
6042 if (m_extraSettings == null)
6043 return;
6044
5878 string oldVal; 6045 string oldVal;
5879 6046
5880 if (m_extraSettings.TryGetValue(name, out oldVal)) 6047 if (m_extraSettings.TryGetValue(name, out oldVal))
@@ -5892,6 +6059,9 @@ Environment.Exit(1);
5892 6059
5893 public void RemoveExtraSetting(string name) 6060 public void RemoveExtraSetting(string name)
5894 { 6061 {
6062 if (m_extraSettings == null)
6063 return;
6064
5895 if (!m_extraSettings.ContainsKey(name)) 6065 if (!m_extraSettings.ContainsKey(name))
5896 return; 6066 return;
5897 6067
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index af13b46..1beb584 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -342,7 +342,7 @@ namespace OpenSim.Region.Framework.Scenes
342 public bool AddNewSceneObject( 342 public bool AddNewSceneObject(
343 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel) 343 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
344 { 344 {
345 AddNewSceneObject(sceneObject, true, false); 345 AddNewSceneObject(sceneObject, attachToBackup, false);
346 346
347 if (pos != null) 347 if (pos != null)
348 sceneObject.AbsolutePosition = (Vector3)pos; 348 sceneObject.AbsolutePosition = (Vector3)pos;
@@ -421,12 +421,9 @@ namespace OpenSim.Region.Framework.Scenes
421 { 421 {
422 Vector3 scale = part.Shape.Scale; 422 Vector3 scale = part.Shape.Scale;
423 423
424 if (scale.X > m_parentScene.m_maxNonphys) 424 scale.X = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.X));
425 scale.X = m_parentScene.m_maxNonphys; 425 scale.Y = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Y));
426 if (scale.Y > m_parentScene.m_maxNonphys) 426 scale.Z = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Z));
427 scale.Y = m_parentScene.m_maxNonphys;
428 if (scale.Z > m_parentScene.m_maxNonphys)
429 scale.Z = m_parentScene.m_maxNonphys;
430 427
431 part.Shape.Scale = scale; 428 part.Shape.Scale = scale;
432 } 429 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index f1b09ca..dba3a61 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -92,7 +92,11 @@ namespace OpenSim.Region.Framework.Scenes
92 private static SceneManager m_instance = null; 92 private static SceneManager m_instance = null;
93 public static SceneManager Instance 93 public static SceneManager Instance
94 { 94 {
95 get { return m_instance; } 95 get {
96 if (m_instance == null)
97 m_instance = new SceneManager();
98 return m_instance;
99 }
96 } 100 }
97 101
98 private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>(); 102 private readonly DoubleDictionary<UUID, string, Scene> m_localScenes = new DoubleDictionary<UUID, string, Scene>();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 053bfb4..985f0a0 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -2742,6 +2742,25 @@ namespace OpenSim.Region.Framework.Scenes
2742 if (objectGroup == this) 2742 if (objectGroup == this)
2743 return; 2743 return;
2744 2744
2745 // If the configured linkset capacity is greater than zero,
2746 // and the new linkset would have a prim count higher than this
2747 // value, do not link it.
2748 if (m_scene.m_linksetCapacity > 0 &&
2749 (PrimCount + objectGroup.PrimCount) >
2750 m_scene.m_linksetCapacity)
2751 {
2752 m_log.DebugFormat(
2753 "[SCENE OBJECT GROUP]: Cannot link group with root" +
2754 " part {0}, {1} ({2} prims) to group with root part" +
2755 " {3}, {4} ({5} prims) because the new linkset" +
2756 " would exceed the configured maximum of {6}",
2757 objectGroup.RootPart.Name, objectGroup.RootPart.UUID,
2758 objectGroup.PrimCount, RootPart.Name, RootPart.UUID,
2759 PrimCount, m_scene.m_linksetCapacity);
2760
2761 return;
2762 }
2763
2745 // 'linkPart' == the root of the group being linked into this group 2764 // 'linkPart' == the root of the group being linked into this group
2746 SceneObjectPart linkPart = objectGroup.m_rootPart; 2765 SceneObjectPart linkPart = objectGroup.m_rootPart;
2747 2766
@@ -3479,27 +3498,33 @@ namespace OpenSim.Region.Framework.Scenes
3479 /// <param name="scale"></param> 3498 /// <param name="scale"></param>
3480 public void GroupResize(Vector3 scale) 3499 public void GroupResize(Vector3 scale)
3481 { 3500 {
3482 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3501// m_log.DebugFormat(
3483 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3502// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
3484 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
3485 3503
3486 PhysicsActor pa = m_rootPart.PhysActor; 3504 PhysicsActor pa = m_rootPart.PhysActor;
3487 3505
3488 if (pa != null && pa.IsPhysical) 3506 if (Scene != null)
3489 { 3507 {
3490 scale.X = Math.Min(scale.X, Scene.m_maxPhys); 3508 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
3491 scale.Y = Math.Min(scale.Y, Scene.m_maxPhys); 3509 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
3492 scale.Z = Math.Min(scale.Z, Scene.m_maxPhys); 3510 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
3511
3512 if (pa != null && pa.IsPhysical)
3513 {
3514 scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X));
3515 scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y));
3516 scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z));
3517 }
3493 } 3518 }
3494 3519
3495 float x = (scale.X / RootPart.Scale.X); 3520 float x = (scale.X / RootPart.Scale.X);
3496 float y = (scale.Y / RootPart.Scale.Y); 3521 float y = (scale.Y / RootPart.Scale.Y);
3497 float z = (scale.Z / RootPart.Scale.Z); 3522 float z = (scale.Z / RootPart.Scale.Z);
3498 3523
3499 SceneObjectPart[] parts; 3524 SceneObjectPart[] parts = m_parts.GetArray();
3500 if (x > 1.0f || y > 1.0f || z > 1.0f) 3525
3526 if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f))
3501 { 3527 {
3502 parts = m_parts.GetArray();
3503 for (int i = 0; i < parts.Length; i++) 3528 for (int i = 0; i < parts.Length; i++)
3504 { 3529 {
3505 SceneObjectPart obPart = parts[i]; 3530 SceneObjectPart obPart = parts[i];
@@ -3512,7 +3537,7 @@ namespace OpenSim.Region.Framework.Scenes
3512 3537
3513 if (pa != null && pa.IsPhysical) 3538 if (pa != null && pa.IsPhysical)
3514 { 3539 {
3515 if (oldSize.X * x > m_scene.m_maxPhys) 3540 if (oldSize.X * x > Scene.m_maxPhys)
3516 { 3541 {
3517 f = m_scene.m_maxPhys / oldSize.X; 3542 f = m_scene.m_maxPhys / oldSize.X;
3518 a = f / x; 3543 a = f / x;
@@ -3520,8 +3545,16 @@ namespace OpenSim.Region.Framework.Scenes
3520 y *= a; 3545 y *= a;
3521 z *= a; 3546 z *= a;
3522 } 3547 }
3548 else if (oldSize.X * x < Scene.m_minPhys)
3549 {
3550 f = m_scene.m_minPhys / oldSize.X;
3551 a = f / x;
3552 x *= a;
3553 y *= a;
3554 z *= a;
3555 }
3523 3556
3524 if (oldSize.Y * y > m_scene.m_maxPhys) 3557 if (oldSize.Y * y > Scene.m_maxPhys)
3525 { 3558 {
3526 f = m_scene.m_maxPhys / oldSize.Y; 3559 f = m_scene.m_maxPhys / oldSize.Y;
3527 a = f / y; 3560 a = f / y;
@@ -3529,8 +3562,16 @@ namespace OpenSim.Region.Framework.Scenes
3529 y *= a; 3562 y *= a;
3530 z *= a; 3563 z *= a;
3531 } 3564 }
3565 else if (oldSize.Y * y < Scene.m_minPhys)
3566 {
3567 f = m_scene.m_minPhys / oldSize.Y;
3568 a = f / y;
3569 x *= a;
3570 y *= a;
3571 z *= a;
3572 }
3532 3573
3533 if (oldSize.Z * z > m_scene.m_maxPhys) 3574 if (oldSize.Z * z > Scene.m_maxPhys)
3534 { 3575 {
3535 f = m_scene.m_maxPhys / oldSize.Z; 3576 f = m_scene.m_maxPhys / oldSize.Z;
3536 a = f / z; 3577 a = f / z;
@@ -3538,10 +3579,18 @@ namespace OpenSim.Region.Framework.Scenes
3538 y *= a; 3579 y *= a;
3539 z *= a; 3580 z *= a;
3540 } 3581 }
3582 else if (oldSize.Z * z < Scene.m_minPhys)
3583 {
3584 f = m_scene.m_minPhys / oldSize.Z;
3585 a = f / z;
3586 x *= a;
3587 y *= a;
3588 z *= a;
3589 }
3541 } 3590 }
3542 else 3591 else
3543 { 3592 {
3544 if (oldSize.X * x > m_scene.m_maxNonphys) 3593 if (oldSize.X * x > Scene.m_maxNonphys)
3545 { 3594 {
3546 f = m_scene.m_maxNonphys / oldSize.X; 3595 f = m_scene.m_maxNonphys / oldSize.X;
3547 a = f / x; 3596 a = f / x;
@@ -3549,8 +3598,16 @@ namespace OpenSim.Region.Framework.Scenes
3549 y *= a; 3598 y *= a;
3550 z *= a; 3599 z *= a;
3551 } 3600 }
3601 else if (oldSize.X * x < Scene.m_minNonphys)
3602 {
3603 f = m_scene.m_minNonphys / oldSize.X;
3604 a = f / x;
3605 x *= a;
3606 y *= a;
3607 z *= a;
3608 }
3552 3609
3553 if (oldSize.Y * y > m_scene.m_maxNonphys) 3610 if (oldSize.Y * y > Scene.m_maxNonphys)
3554 { 3611 {
3555 f = m_scene.m_maxNonphys / oldSize.Y; 3612 f = m_scene.m_maxNonphys / oldSize.Y;
3556 a = f / y; 3613 a = f / y;
@@ -3558,8 +3615,16 @@ namespace OpenSim.Region.Framework.Scenes
3558 y *= a; 3615 y *= a;
3559 z *= a; 3616 z *= a;
3560 } 3617 }
3618 else if (oldSize.Y * y < Scene.m_minNonphys)
3619 {
3620 f = m_scene.m_minNonphys / oldSize.Y;
3621 a = f / y;
3622 x *= a;
3623 y *= a;
3624 z *= a;
3625 }
3561 3626
3562 if (oldSize.Z * z > m_scene.m_maxNonphys) 3627 if (oldSize.Z * z > Scene.m_maxNonphys)
3563 { 3628 {
3564 f = m_scene.m_maxNonphys / oldSize.Z; 3629 f = m_scene.m_maxNonphys / oldSize.Z;
3565 a = f / z; 3630 a = f / z;
@@ -3567,6 +3632,14 @@ namespace OpenSim.Region.Framework.Scenes
3567 y *= a; 3632 y *= a;
3568 z *= a; 3633 z *= a;
3569 } 3634 }
3635 else if (oldSize.Z * z < Scene.m_minNonphys)
3636 {
3637 f = m_scene.m_minNonphys / oldSize.Z;
3638 a = f / z;
3639 x *= a;
3640 y *= a;
3641 z *= a;
3642 }
3570 } 3643 }
3571 } 3644 }
3572 } 3645 }
@@ -3579,7 +3652,6 @@ namespace OpenSim.Region.Framework.Scenes
3579 3652
3580 RootPart.Resize(prevScale); 3653 RootPart.Resize(prevScale);
3581 3654
3582 parts = m_parts.GetArray();
3583 for (int i = 0; i < parts.Length; i++) 3655 for (int i = 0; i < parts.Length; i++)
3584 { 3656 {
3585 SceneObjectPart obPart = parts[i]; 3657 SceneObjectPart obPart = parts[i];
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 3274cbd..2d90a22 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -790,7 +790,7 @@ namespace OpenSim.Region.Framework.Scenes
790 } 790 }
791 catch (Exception e) 791 catch (Exception e)
792 { 792 {
793 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 793 m_log.ErrorFormat("[SCENEOBJECTPART]: GROUP POSITION. {0}", e);
794 } 794 }
795 } 795 }
796 } 796 }
@@ -2972,17 +2972,20 @@ namespace OpenSim.Region.Framework.Scenes
2972 /// <param name="scale"></param> 2972 /// <param name="scale"></param>
2973 public void Resize(Vector3 scale) 2973 public void Resize(Vector3 scale)
2974 { 2974 {
2975 scale.X = Math.Min(scale.X, ParentGroup.Scene.m_maxNonphys);
2976 scale.Y = Math.Min(scale.Y, ParentGroup.Scene.m_maxNonphys);
2977 scale.Z = Math.Min(scale.Z, ParentGroup.Scene.m_maxNonphys);
2978
2979 PhysicsActor pa = PhysActor; 2975 PhysicsActor pa = PhysActor;
2980 2976
2981 if (pa != null && pa.IsPhysical) 2977 if (ParentGroup.Scene != null)
2982 { 2978 {
2983 scale.X = Math.Min(scale.X, ParentGroup.Scene.m_maxPhys); 2979 scale.X = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.X));
2984 scale.Y = Math.Min(scale.Y, ParentGroup.Scene.m_maxPhys); 2980 scale.Y = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Y));
2985 scale.Z = Math.Min(scale.Z, ParentGroup.Scene.m_maxPhys); 2981 scale.Z = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Z));
2982
2983 if (pa != null && pa.IsPhysical)
2984 {
2985 scale.X = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.X));
2986 scale.Y = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Y));
2987 scale.Z = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Z));
2988 }
2986 } 2989 }
2987 2990
2988// m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale); 2991// m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale);
@@ -3079,7 +3082,7 @@ namespace OpenSim.Region.Framework.Scenes
3079 // UUID, Name, TimeStampFull); 3082 // UUID, Name, TimeStampFull);
3080 3083
3081 if (ParentGroup.Scene != null) 3084 if (ParentGroup.Scene != null)
3082 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); 3085 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true);
3083 } 3086 }
3084 3087
3085 /// <summary> 3088 /// <summary>
@@ -3113,7 +3116,7 @@ namespace OpenSim.Region.Framework.Scenes
3113 } 3116 }
3114 3117
3115 if (ParentGroup.Scene != null) 3118 if (ParentGroup.Scene != null)
3116 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); 3119 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false);
3117 } 3120 }
3118 3121
3119 public void ScriptSetPhysicsStatus(bool UsePhysics) 3122 public void ScriptSetPhysicsStatus(bool UsePhysics)
@@ -3567,23 +3570,32 @@ namespace OpenSim.Region.Framework.Scenes
3567 } 3570 }
3568 3571
3569 /// <summary> 3572 /// <summary>
3570 /// Set the color of prim faces 3573 /// Set the color & alpha of prim faces
3571 /// </summary> 3574 /// </summary>
3572 /// <param name="color"></param>
3573 /// <param name="face"></param> 3575 /// <param name="face"></param>
3574 public void SetFaceColor(Vector3 color, int face) 3576 /// <param name="color"></param>
3577 /// <param name="alpha"></param>
3578 public void SetFaceColorAlpha(int face, Vector3 color, double ?alpha)
3575 { 3579 {
3580 Vector3 clippedColor = Util.Clip(color, 0.0f, 1.0f);
3581 float clippedAlpha = alpha.HasValue ?
3582 Util.Clip((float)alpha.Value, 0.0f, 1.0f) : 0;
3583
3576 // The only way to get a deep copy/ If we don't do this, we can 3584 // The only way to get a deep copy/ If we don't do this, we can
3577 // mever detect color changes further down. 3585 // never detect color changes further down.
3578 Byte[] buf = Shape.Textures.GetBytes(); 3586 Byte[] buf = Shape.Textures.GetBytes();
3579 Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length); 3587 Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length);
3580 Color4 texcolor; 3588 Color4 texcolor;
3581 if (face >= 0 && face < GetNumberOfSides()) 3589 if (face >= 0 && face < GetNumberOfSides())
3582 { 3590 {
3583 texcolor = tex.CreateFace((uint)face).RGBA; 3591 texcolor = tex.CreateFace((uint)face).RGBA;
3584 texcolor.R = Util.Clip((float)color.X, 0.0f, 1.0f); 3592 texcolor.R = clippedColor.X;
3585 texcolor.G = Util.Clip((float)color.Y, 0.0f, 1.0f); 3593 texcolor.G = clippedColor.Y;
3586 texcolor.B = Util.Clip((float)color.Z, 0.0f, 1.0f); 3594 texcolor.B = clippedColor.Z;
3595 if (alpha.HasValue)
3596 {
3597 texcolor.A = clippedAlpha;
3598 }
3587 tex.FaceTextures[face].RGBA = texcolor; 3599 tex.FaceTextures[face].RGBA = texcolor;
3588 UpdateTextureEntry(tex.GetBytes()); 3600 UpdateTextureEntry(tex.GetBytes());
3589 return; 3601 return;
@@ -3595,15 +3607,23 @@ namespace OpenSim.Region.Framework.Scenes
3595 if (tex.FaceTextures[i] != null) 3607 if (tex.FaceTextures[i] != null)
3596 { 3608 {
3597 texcolor = tex.FaceTextures[i].RGBA; 3609 texcolor = tex.FaceTextures[i].RGBA;
3598 texcolor.R = Util.Clip((float)color.X, 0.0f, 1.0f); 3610 texcolor.R = clippedColor.X;
3599 texcolor.G = Util.Clip((float)color.Y, 0.0f, 1.0f); 3611 texcolor.G = clippedColor.Y;
3600 texcolor.B = Util.Clip((float)color.Z, 0.0f, 1.0f); 3612 texcolor.B = clippedColor.Z;
3613 if (alpha.HasValue)
3614 {
3615 texcolor.A = clippedAlpha;
3616 }
3601 tex.FaceTextures[i].RGBA = texcolor; 3617 tex.FaceTextures[i].RGBA = texcolor;
3602 } 3618 }
3603 texcolor = tex.DefaultTexture.RGBA; 3619 texcolor = tex.DefaultTexture.RGBA;
3604 texcolor.R = Util.Clip((float)color.X, 0.0f, 1.0f); 3620 texcolor.R = clippedColor.X;
3605 texcolor.G = Util.Clip((float)color.Y, 0.0f, 1.0f); 3621 texcolor.G = clippedColor.Y;
3606 texcolor.B = Util.Clip((float)color.Z, 0.0f, 1.0f); 3622 texcolor.B = clippedColor.Z;
3623 if (alpha.HasValue)
3624 {
3625 texcolor.A = clippedAlpha;
3626 }
3607 tex.DefaultTexture.RGBA = texcolor; 3627 tex.DefaultTexture.RGBA = texcolor;
3608 } 3628 }
3609 UpdateTextureEntry(tex.GetBytes()); 3629 UpdateTextureEntry(tex.GetBytes());
@@ -4891,6 +4911,57 @@ namespace OpenSim.Region.Framework.Scenes
4891 ScheduleFullUpdate(); 4911 ScheduleFullUpdate();
4892 } 4912 }
4893 4913
4914 public void UpdateSlice(float begin, float end)
4915 {
4916 if (end < begin)
4917 {
4918 float temp = begin;
4919 begin = end;
4920 end = temp;
4921 }
4922 end = Math.Min(1f, Math.Max(0f, end));
4923 begin = Math.Min(Math.Min(1f, Math.Max(0f, begin)), end - 0.02f);
4924 if (begin < 0.02f && end < 0.02f)
4925 {
4926 begin = 0f;
4927 end = 0.02f;
4928 }
4929
4930 ushort uBegin = (ushort)(50000.0 * begin);
4931 ushort uEnd = (ushort)(50000.0 * (1f - end));
4932 bool updatePossiblyNeeded = false;
4933 PrimType primType = GetPrimType();
4934 if (primType == PrimType.SPHERE || primType == PrimType.TORUS || primType == PrimType.TUBE || primType == PrimType.RING)
4935 {
4936 if (m_shape.ProfileBegin != uBegin || m_shape.ProfileEnd != uEnd)
4937 {
4938 m_shape.ProfileBegin = uBegin;
4939 m_shape.ProfileEnd = uEnd;
4940 updatePossiblyNeeded = true;
4941 }
4942 }
4943 else if (m_shape.PathBegin != uBegin || m_shape.PathEnd != uEnd)
4944 {
4945 m_shape.PathBegin = uBegin;
4946 m_shape.PathEnd = uEnd;
4947 updatePossiblyNeeded = true;
4948 }
4949
4950 if (updatePossiblyNeeded && ParentGroup != null)
4951 {
4952 ParentGroup.HasGroupChanged = true;
4953 }
4954 if (updatePossiblyNeeded && PhysActor != null)
4955 {
4956 PhysActor.Shape = m_shape;
4957 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
4958 }
4959 if (updatePossiblyNeeded)
4960 {
4961 ScheduleFullUpdate();
4962 }
4963 }
4964
4894 /// <summary> 4965 /// <summary>
4895 /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics 4966 /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics
4896 /// engine can use it. 4967 /// engine can use it.
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index a8aa551..adb3d38 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -974,7 +974,9 @@ namespace OpenSim.Region.Framework.Scenes
974 { 974 {
975 if (wasChild && HasAttachments()) 975 if (wasChild && HasAttachments())
976 { 976 {
977 m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments..."); 977 m_log.DebugFormat(
978 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
979
978 // Resume scripts 980 // Resume scripts
979 Util.FireAndForget(delegate(object x) { 981 Util.FireAndForget(delegate(object x) {
980 foreach (SceneObjectGroup sog in m_attachments) 982 foreach (SceneObjectGroup sog in m_attachments)
@@ -1530,17 +1532,22 @@ namespace OpenSim.Region.Framework.Scenes
1530 bool DCFlagKeyPressed = false; 1532 bool DCFlagKeyPressed = false;
1531 Vector3 agent_control_v3 = Vector3.Zero; 1533 Vector3 agent_control_v3 = Vector3.Zero;
1532 1534
1533 bool oldflying = Flying; 1535 bool newFlying = actor.Flying;
1534 1536
1535 if (ForceFly) 1537 if (ForceFly)
1536 actor.Flying = true; 1538 newFlying = true;
1537 else if (FlyDisabled) 1539 else if (FlyDisabled)
1538 actor.Flying = false; 1540 newFlying = false;
1539 else 1541 else
1540 actor.Flying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); 1542 newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1541 1543
1542 if (actor.Flying != oldflying) 1544 if (actor.Flying != newFlying)
1545 {
1546 // Note: ScenePresence.Flying is actually fetched from the physical actor
1547 // so setting PhysActor.Flying here also sets the ScenePresence's value.
1548 actor.Flying = newFlying;
1543 update_movementflag = true; 1549 update_movementflag = true;
1550 }
1544 1551
1545 if (ParentID == 0) 1552 if (ParentID == 0)
1546 { 1553 {
@@ -3627,13 +3634,16 @@ namespace OpenSim.Region.Framework.Scenes
3627 public List<SceneObjectGroup> GetAttachments(uint attachmentPoint) 3634 public List<SceneObjectGroup> GetAttachments(uint attachmentPoint)
3628 { 3635 {
3629 List<SceneObjectGroup> attachments = new List<SceneObjectGroup>(); 3636 List<SceneObjectGroup> attachments = new List<SceneObjectGroup>();
3630 3637
3631 lock (m_attachments) 3638 if (attachmentPoint >= 0)
3632 { 3639 {
3633 foreach (SceneObjectGroup so in m_attachments) 3640 lock (m_attachments)
3634 { 3641 {
3635 if (attachmentPoint == so.AttachmentPoint) 3642 foreach (SceneObjectGroup so in m_attachments)
3636 attachments.Add(so); 3643 {
3644 if (attachmentPoint == so.AttachmentPoint)
3645 attachments.Add(so);
3646 }
3637 } 3647 }
3638 } 3648 }
3639 3649
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 756b1f4..0d359b9 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -47,6 +47,7 @@ namespace OpenSim.Region.Framework.Scenes
47 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 47 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates"; 49 public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates";
50 public const string SlowFramesStatName = "SlowFrames";
50 51
51 public delegate void SendStatResult(SimStats stats); 52 public delegate void SendStatResult(SimStats stats);
52 53
@@ -129,6 +130,16 @@ namespace OpenSim.Region.Framework.Scenes
129 } 130 }
130 131
131 /// <summary> 132 /// <summary>
133 /// Number of frames that have taken longer to process than Scene.MIN_FRAME_TIME
134 /// </summary>
135 public Stat SlowFramesStat { get; private set; }
136
137 /// <summary>
138 /// The threshold at which we log a slow frame.
139 /// </summary>
140 public int SlowFramesStatReportThreshold { get; private set; }
141
142 /// <summary>
132 /// Extra sim statistics that are used by monitors but not sent to the client. 143 /// Extra sim statistics that are used by monitors but not sent to the client.
133 /// </summary> 144 /// </summary>
134 /// <value> 145 /// <value>
@@ -226,6 +237,22 @@ namespace OpenSim.Region.Framework.Scenes
226 237
227 if (StatsManager.SimExtraStats != null) 238 if (StatsManager.SimExtraStats != null)
228 OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket; 239 OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket;
240
241 /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
242 /// longer than ideal (which in itself is a concern).
243 SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2);
244
245 SlowFramesStat
246 = new Stat(
247 "SlowFrames",
248 "Slow Frames",
249 " frames",
250 "scene",
251 m_scene.Name,
252 StatVerbosity.Info,
253 "Number of frames where frame time has been significantly longer than the desired frame time.");
254
255 StatsManager.RegisterStat(SlowFramesStat);
229 } 256 }
230 257
231 public void Close() 258 public void Close()
@@ -443,6 +470,7 @@ namespace OpenSim.Region.Framework.Scenes
443 lock (m_lastReportedExtraSimStats) 470 lock (m_lastReportedExtraSimStats)
444 { 471 {
445 m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor; 472 m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor;
473 m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value;
446 474
447 Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats(); 475 Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats();
448 476
@@ -563,6 +591,11 @@ namespace OpenSim.Region.Framework.Scenes
563 public void addFrameMS(int ms) 591 public void addFrameMS(int ms)
564 { 592 {
565 m_frameMS += ms; 593 m_frameMS += ms;
594
595 // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
596 // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern).
597 if (ms > SlowFramesStatReportThreshold)
598 SlowFramesStat.Value++;
566 } 599 }
567 600
568 public void addNetMS(int ms) 601 public void addNetMS(int ms)
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index 5758869..5faf131 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -141,7 +141,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
141 TestScene scene = new SceneHelpers().SetupScene(); 141 TestScene scene = new SceneHelpers().SetupScene();
142 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); 142 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
143 143
144 scene.IncomingCloseAgent(sp.UUID); 144 scene.IncomingCloseAgent(sp.UUID, false);
145 145
146 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); 146 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null);
147 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); 147 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
index 44d2d45..9457ebb 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
@@ -50,9 +50,41 @@ using OpenSim.Tests.Common.Mock;
50namespace OpenSim.Region.Framework.Tests 50namespace OpenSim.Region.Framework.Tests
51{ 51{
52 [TestFixture] 52 [TestFixture]
53 public class UserInventoryTests 53 public class UserInventoryTests : OpenSimTestCase
54 { 54 {
55 [Test] 55 [Test]
56 public void TestCreateInventoryFolders()
57 {
58 TestHelpers.InMethod();
59// TestHelpers.EnableLogging();
60
61 // For this test both folders will have the same name which is legal in SL user inventories.
62 string foldersName = "f1";
63
64 Scene scene = new SceneHelpers().SetupScene();
65 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
66
67 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName);
68
69 List<InventoryFolderBase> oneFolder
70 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
71
72 Assert.That(oneFolder.Count, Is.EqualTo(1));
73 InventoryFolderBase firstRetrievedFolder = oneFolder[0];
74 Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName));
75
76 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName);
77
78 List<InventoryFolderBase> twoFolders
79 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
80
81 Assert.That(twoFolders.Count, Is.EqualTo(2));
82 Assert.That(twoFolders[0].Name, Is.EqualTo(foldersName));
83 Assert.That(twoFolders[1].Name, Is.EqualTo(foldersName));
84 Assert.That(twoFolders[0].ID, Is.Not.EqualTo(twoFolders[1].ID));
85 }
86
87 [Test]
56 public void TestGiveInventoryItem() 88 public void TestGiveInventoryItem()
57 { 89 {
58 TestHelpers.InMethod(); 90 TestHelpers.InMethod();
@@ -83,7 +115,7 @@ namespace OpenSim.Region.Framework.Tests
83 public void TestGiveInventoryFolder() 115 public void TestGiveInventoryFolder()
84 { 116 {
85 TestHelpers.InMethod(); 117 TestHelpers.InMethod();
86// log4net.Config.XmlConfigurator.Configure(); 118// TestHelpers.EnableLogging();
87 119
88 Scene scene = new SceneHelpers().SetupScene(); 120 Scene scene = new SceneHelpers().SetupScene();
89 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); 121 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index 411e421..b5ef7b0 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -52,26 +52,23 @@ namespace OpenSim.Region.Framework.Scenes
52 public class UuidGatherer 52 public class UuidGatherer
53 { 53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 /// <summary>
57 /// Asset cache used for gathering assets
58 /// </summary>
59 protected IAssetService m_assetCache;
60
61 /// <summary>
62 /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
63 /// asset was found by the asset service.
64 /// </summary>
65 private AssetBase m_requestedObjectAsset;
66 55
67 /// <summary> 56 protected IAssetService m_assetService;
68 /// Signal whether we are currently waiting for the asset service to deliver an asset. 57
69 /// </summary> 58// /// <summary>
70 private bool m_waitingForObjectAsset; 59// /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
60// /// asset was found by the asset service.
61// /// </summary>
62// private AssetBase m_requestedObjectAsset;
63//
64// /// <summary>
65// /// Signal whether we are currently waiting for the asset service to deliver an asset.
66// /// </summary>
67// private bool m_waitingForObjectAsset;
71 68
72 public UuidGatherer(IAssetService assetCache) 69 public UuidGatherer(IAssetService assetCache)
73 { 70 {
74 m_assetCache = assetCache; 71 m_assetService = assetCache;
75 } 72 }
76 73
77 /// <summary> 74 /// <summary>
@@ -191,18 +188,18 @@ namespace OpenSim.Region.Framework.Scenes
191 } 188 }
192 } 189 }
193 190
194 /// <summary> 191// /// <summary>
195 /// The callback made when we request the asset for an object from the asset service. 192// /// The callback made when we request the asset for an object from the asset service.
196 /// </summary> 193// /// </summary>
197 private void AssetReceived(string id, Object sender, AssetBase asset) 194// private void AssetReceived(string id, Object sender, AssetBase asset)
198 { 195// {
199 lock (this) 196// lock (this)
200 { 197// {
201 m_requestedObjectAsset = asset; 198// m_requestedObjectAsset = asset;
202 m_waitingForObjectAsset = false; 199// m_waitingForObjectAsset = false;
203 Monitor.Pulse(this); 200// Monitor.Pulse(this);
204 } 201// }
205 } 202// }
206 203
207 /// <summary> 204 /// <summary>
208 /// Get an asset synchronously, potentially using an asynchronous callback. If the 205 /// Get an asset synchronously, potentially using an asynchronous callback. If the
@@ -212,25 +209,29 @@ namespace OpenSim.Region.Framework.Scenes
212 /// <returns></returns> 209 /// <returns></returns>
213 protected virtual AssetBase GetAsset(UUID uuid) 210 protected virtual AssetBase GetAsset(UUID uuid)
214 { 211 {
215 m_waitingForObjectAsset = true; 212 return m_assetService.Get(uuid.ToString());
216 m_assetCache.Get(uuid.ToString(), this, AssetReceived);
217
218 // The asset cache callback can either
219 //
220 // 1. Complete on the same thread (if the asset is already in the cache) or
221 // 2. Come in via a different thread (if we need to go fetch it).
222 //
223 // The code below handles both these alternatives.
224 lock (this)
225 {
226 if (m_waitingForObjectAsset)
227 {
228 Monitor.Wait(this);
229 m_waitingForObjectAsset = false;
230 }
231 }
232 213
233 return m_requestedObjectAsset; 214 // XXX: Switching to do this synchronously where the call was async before but we always waited for it
215 // to complete anyway!
216// m_waitingForObjectAsset = true;
217// m_assetCache.Get(uuid.ToString(), this, AssetReceived);
218//
219// // The asset cache callback can either
220// //
221// // 1. Complete on the same thread (if the asset is already in the cache) or
222// // 2. Come in via a different thread (if we need to go fetch it).
223// //
224// // The code below handles both these alternatives.
225// lock (this)
226// {
227// if (m_waitingForObjectAsset)
228// {
229// Monitor.Wait(this);
230// m_waitingForObjectAsset = false;
231// }
232// }
233//
234// return m_requestedObjectAsset;
234 } 235 }
235 236
236 /// <summary> 237 /// <summary>
@@ -361,4 +362,47 @@ namespace OpenSim.Region.Framework.Scenes
361 } 362 }
362 } 363 }
363 } 364 }
365
366 public class HGUuidGatherer : UuidGatherer
367 {
368 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
369
370 protected string m_assetServerURL;
371
372 public HGUuidGatherer(IAssetService assetService, string assetServerURL)
373 : base(assetService)
374 {
375 m_assetServerURL = assetServerURL;
376 if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))
377 m_assetServerURL = m_assetServerURL + "/";
378 }
379
380 protected override AssetBase GetAsset(UUID uuid)
381 {
382 if (string.Empty == m_assetServerURL)
383 return base.GetAsset(uuid);
384 else
385 return FetchAsset(uuid);
386 }
387
388 public AssetBase FetchAsset(UUID assetID)
389 {
390
391 // Test if it's already here
392 AssetBase asset = m_assetService.Get(assetID.ToString());
393 if (asset == null)
394 {
395 // It's not, so fetch it from abroad
396 asset = m_assetService.Get(m_assetServerURL + assetID.ToString());
397 if (asset != null)
398 m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL);
399 else
400 m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL);
401 }
402 //else
403 // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL);
404
405 return asset;
406 }
407 }
364} 408}
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index a484300..f3382b2 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -890,10 +890,10 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
890 890
891 public void Close() 891 public void Close()
892 { 892 {
893 Close(true); 893 Close(true, false);
894 } 894 }
895 895
896 public void Close(bool sendStop) 896 public void Close(bool sendStop, bool force)
897 { 897 {
898 Disconnect(); 898 Disconnect();
899 } 899 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
index 31d0034..17971e3 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
@@ -130,37 +130,37 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
130 SendConsoleOutput(agentID, String.Format("auto_grant_attach_perms set to {0}", val)); 130 SendConsoleOutput(agentID, String.Format("auto_grant_attach_perms set to {0}", val));
131 } 131 }
132 132
133 private void llAttachToAvatarTemp(UUID host, UUID script, int attachmentPoint) 133 private int llAttachToAvatarTemp(UUID host, UUID script, int attachmentPoint)
134 { 134 {
135 SceneObjectPart hostPart = m_scene.GetSceneObjectPart(host); 135 SceneObjectPart hostPart = m_scene.GetSceneObjectPart(host);
136 136
137 if (hostPart == null) 137 if (hostPart == null)
138 return; 138 return 0;
139 139
140 if (hostPart.ParentGroup.IsAttachment) 140 if (hostPart.ParentGroup.IsAttachment)
141 return; 141 return 0;
142 142
143 IAttachmentsModule attachmentsModule = m_scene.RequestModuleInterface<IAttachmentsModule>(); 143 IAttachmentsModule attachmentsModule = m_scene.RequestModuleInterface<IAttachmentsModule>();
144 if (attachmentsModule == null) 144 if (attachmentsModule == null)
145 return; 145 return 0;
146 146
147 TaskInventoryItem item = hostPart.Inventory.GetInventoryItem(script); 147 TaskInventoryItem item = hostPart.Inventory.GetInventoryItem(script);
148 if (item == null) 148 if (item == null)
149 return; 149 return 0;
150 150
151 if ((item.PermsMask & 32) == 0) // PERMISSION_ATTACH 151 if ((item.PermsMask & 32) == 0) // PERMISSION_ATTACH
152 return; 152 return 0;
153 153
154 ScenePresence target; 154 ScenePresence target;
155 if (!m_scene.TryGetScenePresence(item.PermsGranter, out target)) 155 if (!m_scene.TryGetScenePresence(item.PermsGranter, out target))
156 return; 156 return 0;
157 157
158 if (target.UUID != hostPart.ParentGroup.OwnerID) 158 if (target.UUID != hostPart.ParentGroup.OwnerID)
159 { 159 {
160 uint effectivePerms = hostPart.ParentGroup.GetEffectivePermissions(); 160 uint effectivePerms = hostPart.ParentGroup.GetEffectivePermissions();
161 161
162 if ((effectivePerms & (uint)PermissionMask.Transfer) == 0) 162 if ((effectivePerms & (uint)PermissionMask.Transfer) == 0)
163 return; 163 return 0;
164 164
165 hostPart.ParentGroup.SetOwnerId(target.UUID); 165 hostPart.ParentGroup.SetOwnerId(target.UUID);
166 hostPart.ParentGroup.SetRootPartOwner(hostPart.ParentGroup.RootPart, target.UUID, target.ControllingClient.ActiveGroupId); 166 hostPart.ParentGroup.SetRootPartOwner(hostPart.ParentGroup.RootPart, target.UUID, target.ControllingClient.ActiveGroupId);
@@ -183,7 +183,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
183 hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); 183 hostPart.ParentGroup.RootPart.ScheduleFullUpdate();
184 } 184 }
185 185
186 attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true); 186 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true) ? 1 : 0;
187 } 187 }
188 } 188 }
189} 189}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index ca956fb..a014798 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -231,12 +231,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
231 if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null) 231 if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
232 throw new Exception("Invalid connector configuration"); 232 throw new Exception("Invalid connector configuration");
233 233
234 // Generate an initial nickname if randomizing is enabled 234 // Generate an initial nickname
235 235
236 if (m_randomizeNick) 236 if (m_randomizeNick)
237 {
238 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
239 } 238 else
239 m_nick = m_baseNick;
240 240
241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); 241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
242 242
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 7b20446..f292a75 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -447,7 +447,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
447 // settings allow voice, then whether parcel allows 447 // settings allow voice, then whether parcel allows
448 // voice, if all do retrieve or obtain the parcel 448 // voice, if all do retrieve or obtain the parcel
449 // voice channel 449 // voice channel
450 LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 450 LandData land = scene.GetLandData(avatar.AbsolutePosition);
451 451
452 //m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", 452 //m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}",
453 // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param); 453 // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index a30a38d..8a8a31c 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -623,7 +623,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
623 // settings allow voice, then whether parcel allows 623 // settings allow voice, then whether parcel allows
624 // voice, if all do retrieve or obtain the parcel 624 // voice, if all do retrieve or obtain the parcel
625 // voice channel 625 // voice channel
626 LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 626 LandData land = scene.GetLandData(avatar.AbsolutePosition);
627 627
628// m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", 628// m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}",
629// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param); 629// scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param);
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
index 311531c..732c28f 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -175,14 +175,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
175 /// 175 ///
176 /// </summary> 176 /// </summary>
177 // ----------------------------------------------------------------- 177 // -----------------------------------------------------------------
178 public bool CreateStore(string value, out UUID result) 178 public bool CreateStore(string value, ref UUID result)
179 { 179 {
180 result = UUID.Zero; 180 if (result == UUID.Zero)
181 result = UUID.Random();
182
183 JsonStore map = null;
181 184
182 if (! m_enabled) return false; 185 if (! m_enabled) return false;
183 186
184 UUID uuid = UUID.Random();
185 JsonStore map = null;
186 187
187 try 188 try
188 { 189 {
@@ -195,9 +196,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
195 } 196 }
196 197
197 lock (m_JsonValueStore) 198 lock (m_JsonValueStore)
198 m_JsonValueStore.Add(uuid,map); 199 m_JsonValueStore.Add(result,map);
199 200
200 result = uuid;
201 return true; 201 return true;
202 } 202 }
203 203
@@ -231,7 +231,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
231 if (! m_JsonValueStore.TryGetValue(storeID,out map)) 231 if (! m_JsonValueStore.TryGetValue(storeID,out map))
232 { 232 {
233 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); 233 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
234 return true; 234 return false;
235 } 235 }
236 } 236 }
237 237
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
index eaba816..6910d14 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -227,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
227 protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) 227 protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value)
228 { 228 {
229 UUID uuid = UUID.Zero; 229 UUID uuid = UUID.Zero;
230 if (! m_store.CreateStore(value, out uuid)) 230 if (! m_store.CreateStore(value, ref uuid))
231 GenerateRuntimeError("Failed to create Json store"); 231 GenerateRuntimeError("Failed to create Json store");
232 232
233 return uuid; 233 return uuid;
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index fff3a32..bad75f7 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -181,7 +181,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
181 } 181 }
182 } 182 }
183 183
184 void OnOarFileLoaded(Guid requestId, string message) 184 void OnOarFileLoaded(Guid requestId, List<UUID> loadedScenes, string message)
185 { 185 {
186 m_oarFileLoading = true; 186 m_oarFileLoading = true;
187 187
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 7c693b6..66fc216 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -148,7 +148,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
148 OnInstantMessage(this, new GridInstantMessage(m_scene, 148 OnInstantMessage(this, new GridInstantMessage(m_scene,
149 m_uuid, m_firstname + " " + m_lastname, 149 m_uuid, m_firstname + " " + m_lastname,
150 target, 0, false, message, 150 target, 0, false, message,
151 UUID.Zero, false, Position, new byte[0])); 151 UUID.Zero, false, Position, new byte[0], true));
152 } 152 }
153 153
154 public void SendAgentOffline(UUID[] agentIDs) 154 public void SendAgentOffline(UUID[] agentIDs)
@@ -909,11 +909,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC
909 909
910 public void Close() 910 public void Close()
911 { 911 {
912 Close(true); 912 Close(true, false);
913 } 913 }
914 914
915 public void Close(bool sendStop) 915 public void Close(bool sendStop, bool force)
916 { 916 {
917 // Remove ourselves from the scene
918 m_scene.RemoveClient(AgentId, false);
917 } 919 }
918 920
919 public void Start() 921 public void Start()
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
index 683bc51..3306a97 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
@@ -34,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public class BS6DofConstraint : BSConstraint 35public class BS6DofConstraint : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
37 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
38 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
39 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
@@ -44,11 +48,14 @@ public class BS6DofConstraint : BSConstraint
44 m_body1 = obj1; 48 m_body1 = obj1;
45 m_body2 = obj2; 49 m_body2 = obj2;
46 m_constraint = new BulletConstraint( 50 m_constraint = new BulletConstraint(
47 BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
48 frame1, frame1rot, 52 frame1, frame1rot,
49 frame2, frame2rot, 53 frame2, frame2rot,
50 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
51 m_enabled = true; 55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
52 } 59 }
53 60
54 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
@@ -58,11 +65,36 @@ public class BS6DofConstraint : BSConstraint
58 m_world = world; 65 m_world = world;
59 m_body1 = obj1; 66 m_body1 = obj1;
60 m_body2 = obj2; 67 m_body2 = obj2;
61 m_constraint = new BulletConstraint( 68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
62 BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 69 {
63 joinPoint, 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
64 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 71 BSScene.DetailLogZero, world.worldID,
65 m_enabled = true; 72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 "[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
75 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
76 m_enabled = false;
77 }
78 else
79 {
80 m_constraint = new BulletConstraint(
81 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
82 joinPoint,
83 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
84 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
85 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
86 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
87 if (m_constraint.ptr == IntPtr.Zero)
88 {
89 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
90 LogHeader, obj1.ID, obj2.ID);
91 m_enabled = false;
92 }
93 else
94 {
95 m_enabled = true;
96 }
97 }
66 } 98 }
67 99
68 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 100 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
@@ -70,7 +102,7 @@ public class BS6DofConstraint : BSConstraint
70 bool ret = false; 102 bool ret = false;
71 if (m_enabled) 103 if (m_enabled)
72 { 104 {
73 BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); 105 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
74 ret = true; 106 ret = true;
75 } 107 }
76 return ret; 108 return ret;
@@ -81,9 +113,9 @@ public class BS6DofConstraint : BSConstraint
81 bool ret = false; 113 bool ret = false;
82 if (m_enabled) 114 if (m_enabled)
83 { 115 {
84 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
85 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
86 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 118 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
87 ret = true; 119 ret = true;
88 } 120 }
89 return ret; 121 return ret;
@@ -94,7 +126,7 @@ public class BS6DofConstraint : BSConstraint
94 bool ret = false; 126 bool ret = false;
95 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 127 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
96 if (m_enabled) 128 if (m_enabled)
97 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); 129 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
98 return ret; 130 return ret;
99 } 131 }
100 132
@@ -103,7 +135,7 @@ public class BS6DofConstraint : BSConstraint
103 bool ret = false; 135 bool ret = false;
104 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 136 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
105 if (m_enabled) 137 if (m_enabled)
106 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); 138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
107 return ret; 139 return ret;
108 } 140 }
109 141
@@ -111,7 +143,7 @@ public class BS6DofConstraint : BSConstraint
111 { 143 {
112 bool ret = false; 144 bool ret = false;
113 if (m_enabled) 145 if (m_enabled)
114 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); 146 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
115 return ret; 147 return ret;
116 } 148 }
117} 149}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index e2f7af9..2e6b2da 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,62 +28,46 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : PhysicsActor 37public class BSCharacter : BSPhysObject
38{ 38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
41 41
42 private BSScene _scene;
43 public BSScene Scene { get { return _scene; } }
44 private String _avName;
45 // private bool _stopped; 42 // private bool _stopped;
46 private Vector3 _size; 43 private OMV.Vector3 _size;
47 private Vector3 _scale; 44 private OMV.Vector3 _scale;
48 private PrimitiveBaseShape _pbs; 45 private PrimitiveBaseShape _pbs;
49 private uint _localID = 0;
50 private bool _grabbed; 46 private bool _grabbed;
51 private bool _selected; 47 private bool _selected;
52 private Vector3 _position; 48 private OMV.Vector3 _position;
53 private float _mass; 49 private float _mass;
54 public float _density; 50 private float _avatarDensity;
55 public float _avatarVolume; 51 private float _avatarVolume;
56 private Vector3 _force; 52 private OMV.Vector3 _force;
57 private Vector3 _velocity; 53 private OMV.Vector3 _velocity;
58 private Vector3 _torque; 54 private OMV.Vector3 _torque;
59 private float _collisionScore; 55 private float _collisionScore;
60 private Vector3 _acceleration; 56 private OMV.Vector3 _acceleration;
61 private Quaternion _orientation; 57 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 58 private int _physicsActorType;
63 private bool _isPhysical; 59 private bool _isPhysical;
64 private bool _flying; 60 private bool _flying;
65 private bool _setAlwaysRun; 61 private bool _setAlwaysRun;
66 private bool _throttleUpdates; 62 private bool _throttleUpdates;
67 private bool _isColliding; 63 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj; 64 private bool _collidingObj;
72 private bool _floatOnWater; 65 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity; 66 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 67 private bool _kinematic;
75 private float _buoyancy; 68 private float _buoyancy;
76 69
77 private BulletBody m_body; 70 private OMV.Vector3 _PIDTarget;
78 public BulletBody Body {
79 get { return m_body; }
80 set { m_body = value; }
81 }
82
83 private int _subscribedEventsMs = 0;
84 private int _nextCollisionOkTime = 0;
85
86 private Vector3 _PIDTarget;
87 private bool _usePID; 71 private bool _usePID;
88 private float _PIDTau; 72 private float _PIDTau;
89 private bool _useHoverPID; 73 private bool _useHoverPID;
@@ -91,25 +75,26 @@ public class BSCharacter : PhysicsActor
91 private PIDHoverType _PIDHoverType; 75 private PIDHoverType _PIDHoverType;
92 private float _PIDHoverTao; 76 private float _PIDHoverTao;
93 77
94 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 78 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
95 { 79 {
96 _localID = localID; 80 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
97 _avName = avName; 81 _physicsActorType = (int)ActorTypes.Agent;
98 _scene = parent_scene;
99 _position = pos; 82 _position = pos;
100 _size = size; 83 _size = size;
101 _flying = isFlying; 84 _flying = isFlying;
102 _orientation = Quaternion.Identity; 85 _orientation = OMV.Quaternion.Identity;
103 _velocity = Vector3.Zero; 86 _velocity = OMV.Vector3.Zero;
104 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 87 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
88
105 // The dimensions of the avatar capsule are kept in the scale. 89 // The dimensions of the avatar capsule are kept in the scale.
106 // Physics creates a unit capsule which is scaled by the physics engine. 90 // Physics creates a unit capsule which is scaled by the physics engine.
107 _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); 91 ComputeAvatarScale(_size);
108 _density = _scene.Params.avatarDensity; 92 _avatarDensity = PhysicsScene.Params.avatarDensity;
109 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 93 // set _avatarVolume and _mass based on capsule size, _density and _scale
94 ComputeAvatarVolumeAndMass();
110 95
111 ShapeData shapeData = new ShapeData(); 96 ShapeData shapeData = new ShapeData();
112 shapeData.ID = _localID; 97 shapeData.ID = LocalID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; 98 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position; 99 shapeData.Position = _position;
115 shapeData.Rotation = _orientation; 100 shapeData.Rotation = _orientation;
@@ -118,29 +103,35 @@ public class BSCharacter : PhysicsActor
118 shapeData.Mass = _mass; 103 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy; 104 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse; 105 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = _scene.Params.avatarFriction; 106 shapeData.Friction = PhysicsScene.Params.avatarFriction;
122 shapeData.Restitution = _scene.Params.avatarRestitution; 107 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
123 108
124 // do actual create at taint time 109 // do actual create at taint time
125 _scene.TaintedObject("BSCharacter.create", delegate() 110 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 111 {
127 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113 BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
114
115 // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
116 // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
117 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
118
119 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
128 120
129 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); 121 // This works here because CreateObject has already put the character into the physical world.
130 // avatars get all collisions no matter what 122 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
131 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 123 (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
132 }); 124 });
133
134 return; 125 return;
135 } 126 }
136 127
137 // called when this character is being destroyed and the resources should be released 128 // called when this character is being destroyed and the resources should be released
138 public void Destroy() 129 public override void Destroy()
139 { 130 {
140 // DetailLog("{0},BSCharacter.Destroy", LocalID); 131 DetailLog("{0},BSCharacter.Destroy", LocalID);
141 _scene.TaintedObject("BSCharacter.destroy", delegate() 132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
142 { 133 {
143 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 134 BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
144 }); 135 });
145 } 136 }
146 137
@@ -149,274 +140,368 @@ public class BSCharacter : PhysicsActor
149 base.RequestPhysicsterseUpdate(); 140 base.RequestPhysicsterseUpdate();
150 } 141 }
151 // No one calls this method so I don't know what it could possibly mean 142 // No one calls this method so I don't know what it could possibly mean
152 public override bool Stopped { 143 public override bool Stopped {
153 get { return false; } 144 get { return false; }
154 } 145 }
155 public override Vector3 Size { 146 public override OMV.Vector3 Size {
156 get 147 get
157 { 148 {
158 // Avatar capsule size is kept in the scale parameter. 149 // Avatar capsule size is kept in the scale parameter.
159 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 150 return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
160 } 151 }
161 152
162 set { 153 set {
163 // When an avatar's size is set, only the height is changed 154 // When an avatar's size is set, only the height is changed
164 // and that really only depends on the radius. 155 // and that really only depends on the radius.
165 _size = value; 156 _size = value;
166 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 157 ComputeAvatarScale(_size);
167 158
168 // TODO: something has to be done with the avatar's vertical position 159 // TODO: something has to be done with the avatar's vertical position
169 160
170 ComputeAvatarVolumeAndMass(); 161 ComputeAvatarVolumeAndMass();
171 162
172 _scene.TaintedObject("BSCharacter.setSize", delegate() 163 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
173 { 164 {
174 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); 165 BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
175 }); 166 });
176 167
177 } 168 }
178 }
179 public override PrimitiveBaseShape Shape {
180 set { _pbs = value;
181 }
182 } 169 }
183 public override uint LocalID { 170 public override PrimitiveBaseShape Shape {
184 set { _localID = value; 171 set { _pbs = value;
185 } 172 }
186 get { return _localID; }
187 } 173 }
188 public override bool Grabbed { 174 public override bool Grabbed {
189 set { _grabbed = value; 175 set { _grabbed = value;
190 } 176 }
191 } 177 }
192 public override bool Selected { 178 public override bool Selected {
193 set { _selected = value; 179 set { _selected = value;
194 } 180 }
195 } 181 }
196 public override void CrossingFailure() { return; } 182 public override void CrossingFailure() { return; }
197 public override void link(PhysicsActor obj) { return; } 183 public override void link(PhysicsActor obj) { return; }
198 public override void delink() { return; } 184 public override void delink() { return; }
199 public override void LockAngularMotion(Vector3 axis) { return; }
200 185
201 public override Vector3 Position { 186 // Set motion values to zero.
187 // Do it to the properties so the values get set in the physics engine.
188 // Push the setting of the values to the viewer.
189 // Called at taint time!
190 public override void ZeroMotion()
191 {
192 _velocity = OMV.Vector3.Zero;
193 _acceleration = OMV.Vector3.Zero;
194 _rotationalVelocity = OMV.Vector3.Zero;
195
196 // Zero some other properties directly into the physics engine
197 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
198 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
199 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
200 BulletSimAPI.ClearForces2(BSBody.ptr);
201 }
202
203 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
204
205 public override OMV.Vector3 Position {
202 get { 206 get {
203 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 207 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
204 return _position; 208 return _position;
205 } 209 }
206 set { 210 set {
207 _position = value; 211 _position = value;
208 PositionSanityCheck(); 212 PositionSanityCheck();
209 213
210 _scene.TaintedObject("BSCharacter.setPosition", delegate() 214 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
211 { 215 {
212 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 216 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
213 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 217 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
214 }); 218 });
215 } 219 }
220 }
221 public override OMV.Vector3 ForcePosition {
222 get {
223 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
224 return _position;
225 }
226 set {
227 _position = value;
228 PositionSanityCheck();
229 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
230 }
216 } 231 }
217 232
233
218 // Check that the current position is sane and, if not, modify the position to make it so. 234 // Check that the current position is sane and, if not, modify the position to make it so.
219 // Check for being below terrain and being out of bounds. 235 // Check for being below terrain and being out of bounds.
220 // Returns 'true' of the position was made sane by some action. 236 // Returns 'true' of the position was made sane by some action.
221 private bool PositionSanityCheck() 237 private bool PositionSanityCheck()
222 { 238 {
223 bool ret = false; 239 bool ret = false;
224 240
225 // If below the ground, move the avatar up 241 // If below the ground, move the avatar up
226 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 242 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
227 if (_position.Z < terrainHeight) 243 if (Position.Z < terrainHeight)
228 { 244 {
229 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 245 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
230 _position.Z = terrainHeight + 2.0f; 246 _position.Z = terrainHeight + 2.0f;
231 ret = true; 247 ret = true;
232 } 248 }
249 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
250 {
251 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
252 if (Position.Z < waterHeight)
253 {
254 _position.Z = waterHeight;
255 ret = true;
256 }
257 }
233 258
234 // TODO: check for out of bounds 259 // TODO: check for out of bounds
260 return ret;
261 }
235 262
263 // A version of the sanity check that also makes sure a new position value is
264 // pushed back to the physics engine. This routine would be used by anyone
265 // who is not already pushing the value.
266 private bool PositionSanityCheck2(bool inTaintTime)
267 {
268 bool ret = false;
269 if (PositionSanityCheck())
270 {
271 // The new position value must be pushed into the physics engine but we can't
272 // just assign to "Position" because of potential call loops.
273 BSScene.TaintCallback sanityOperation = delegate()
274 {
275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
277 };
278 if (inTaintTime)
279 sanityOperation();
280 else
281 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
282 ret = true;
283 }
236 return ret; 284 return ret;
237 } 285 }
238 286
239 public override float Mass { 287 public override float Mass {
240 get { 288 get {
241 return _mass; 289 return _mass;
242 } 290 }
243 } 291 }
244 public override Vector3 Force { 292
245 get { return _force; } 293 // used when we only want this prim's mass and not the linkset thing
294 public override float MassRaw { get {return _mass; } }
295
296 public override OMV.Vector3 Force {
297 get { return _force; }
246 set { 298 set {
247 _force = value; 299 _force = value;
248 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 300 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
249 Scene.TaintedObject("BSCharacter.SetForce", delegate() 301 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
250 { 302 {
251 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 303 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
252 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 304 BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
253 }); 305 });
254 } 306 }
255 } 307 }
256 308
257 public override int VehicleType { 309 public override int VehicleType {
258 get { return 0; } 310 get { return 0; }
259 set { return; } 311 set { return; }
260 } 312 }
261 public override void VehicleFloatParam(int param, float value) { } 313 public override void VehicleFloatParam(int param, float value) { }
262 public override void VehicleVectorParam(int param, Vector3 value) {} 314 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
263 public override void VehicleRotationParam(int param, Quaternion rotation) { } 315 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
264 public override void VehicleFlags(int param, bool remove) { } 316 public override void VehicleFlags(int param, bool remove) { }
265 317
266 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 318 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
267 public override void SetVolumeDetect(int param) { return; } 319 public override void SetVolumeDetect(int param) { return; }
268 320
269 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 321 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
270 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 322 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
271 public override Vector3 Velocity { 323 public override OMV.Vector3 Velocity {
272 get { return _velocity; } 324 get { return _velocity; }
273 set { 325 set {
274 _velocity = value; 326 _velocity = value;
275 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 327 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
276 _scene.TaintedObject("BSCharacter.setVelocity", delegate() 328 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
277 { 329 {
278 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 330 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
279 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); 331 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
280 }); 332 });
281 } 333 }
282 } 334 }
283 public override Vector3 Torque { 335 public override OMV.Vector3 ForceVelocity {
284 get { return _torque; } 336 get { return _velocity; }
285 set { _torque = value; 337 set {
286 } 338 _velocity = value;
339 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
340 }
287 } 341 }
288 public override float CollisionScore { 342 public override OMV.Vector3 Torque {
289 get { return _collisionScore; } 343 get { return _torque; }
290 set { _collisionScore = value; 344 set { _torque = value;
291 } 345 }
346 }
347 public override float CollisionScore {
348 get { return _collisionScore; }
349 set { _collisionScore = value;
350 }
292 } 351 }
293 public override Vector3 Acceleration { 352 public override OMV.Vector3 Acceleration {
294 get { return _acceleration; } 353 get { return _acceleration; }
295 set { _acceleration = value; } 354 set { _acceleration = value; }
296 } 355 }
297 public override Quaternion Orientation { 356 public override OMV.Quaternion Orientation {
298 get { return _orientation; } 357 get { return _orientation; }
299 set { 358 set {
300 _orientation = value; 359 _orientation = value;
301 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 360 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
302 _scene.TaintedObject("BSCharacter.setOrientation", delegate() 361 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
303 { 362 {
304 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 363 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
305 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 364 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
306 }); 365 });
307 } 366 }
367 }
368 // Go directly to Bullet to get/set the value.
369 public override OMV.Quaternion ForceOrientation
370 {
371 get
372 {
373 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
374 return _orientation;
375 }
376 set
377 {
378 _orientation = value;
379 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
380 }
308 } 381 }
309 public override int PhysicsActorType { 382 public override int PhysicsActorType {
310 get { return _physicsActorType; } 383 get { return _physicsActorType; }
311 set { _physicsActorType = value; 384 set { _physicsActorType = value;
312 } 385 }
313 } 386 }
314 public override bool IsPhysical { 387 public override bool IsPhysical {
315 get { return _isPhysical; } 388 get { return _isPhysical; }
316 set { _isPhysical = value; 389 set { _isPhysical = value;
317 } 390 }
318 } 391 }
319 public override bool Flying { 392 public override bool Flying {
320 get { return _flying; } 393 get { return _flying; }
321 set { 394 set {
322 if (_flying != value) 395 _flying = value;
323 { 396 // simulate flying by changing the effect of gravity
324 _flying = value; 397 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
325 // simulate flying by changing the effect of gravity 398 }
326 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
327 }
328 }
329 } 399 }
400 // Flying is implimented by changing the avatar's buoyancy.
401 // Would this be done better with a vehicle type?
330 private float ComputeBuoyancyFromFlying(bool ifFlying) { 402 private float ComputeBuoyancyFromFlying(bool ifFlying) {
331 return ifFlying ? 1f : 0f; 403 return ifFlying ? 1f : 0f;
332 } 404 }
333 public override bool 405 public override bool
334 SetAlwaysRun { 406 SetAlwaysRun {
335 get { return _setAlwaysRun; } 407 get { return _setAlwaysRun; }
336 set { _setAlwaysRun = value; } 408 set { _setAlwaysRun = value; }
337 } 409 }
338 public override bool ThrottleUpdates { 410 public override bool ThrottleUpdates {
339 get { return _throttleUpdates; } 411 get { return _throttleUpdates; }
340 set { _throttleUpdates = value; } 412 set { _throttleUpdates = value; }
341 } 413 }
342 public override bool IsColliding { 414 public override bool IsColliding {
343 get { return (_collidingStep == _scene.SimulationStep); } 415 get { return (CollidingStep == PhysicsScene.SimulationStep); }
344 set { _isColliding = value; } 416 set { _isColliding = value; }
345 } 417 }
346 public override bool CollidingGround { 418 public override bool CollidingGround {
347 get { return (_collidingGroundStep == _scene.SimulationStep); } 419 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
348 set { _collidingGround = value; } 420 set { CollidingGround = value; }
421 }
422 public override bool CollidingObj {
423 get { return _collidingObj; }
424 set { _collidingObj = value; }
349 } 425 }
350 public override bool CollidingObj { 426 public override bool FloatOnWater {
351 get { return _collidingObj; } 427 set {
352 set { _collidingObj = value; } 428 _floatOnWater = value;
429 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
430 {
431 if (_floatOnWater)
432 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
433 else
434 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
435 });
436 }
353 } 437 }
354 public override bool FloatOnWater { 438 public override OMV.Vector3 RotationalVelocity {
355 set { _floatOnWater = value; } 439 get { return _rotationalVelocity; }
440 set { _rotationalVelocity = value; }
356 } 441 }
357 public override Vector3 RotationalVelocity { 442 public override OMV.Vector3 ForceRotationalVelocity {
358 get { return _rotationalVelocity; } 443 get { return _rotationalVelocity; }
359 set { _rotationalVelocity = value; } 444 set { _rotationalVelocity = value; }
360 } 445 }
361 public override bool Kinematic { 446 public override bool Kinematic {
362 get { return _kinematic; } 447 get { return _kinematic; }
363 set { _kinematic = value; } 448 set { _kinematic = value; }
364 } 449 }
365 // neg=fall quickly, 0=1g, 1=0g, pos=float up 450 // neg=fall quickly, 0=1g, 1=0g, pos=float up
366 public override float Buoyancy { 451 public override float Buoyancy {
367 get { return _buoyancy; } 452 get { return _buoyancy; }
368 set { _buoyancy = value; 453 set { _buoyancy = value;
369 _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 454 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
370 { 455 {
371 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 456 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
372 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); 457 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
373 }); 458 });
374 } 459 }
375 } 460 }
376 461
377 // Used for MoveTo 462 // Used for MoveTo
378 public override Vector3 PIDTarget { 463 public override OMV.Vector3 PIDTarget {
379 set { _PIDTarget = value; } 464 set { _PIDTarget = value; }
380 } 465 }
381 public override bool PIDActive { 466 public override bool PIDActive {
382 set { _usePID = value; } 467 set { _usePID = value; }
383 } 468 }
384 public override float PIDTau { 469 public override float PIDTau {
385 set { _PIDTau = value; } 470 set { _PIDTau = value; }
386 } 471 }
387 472
388 // Used for llSetHoverHeight and maybe vehicle height 473 // Used for llSetHoverHeight and maybe vehicle height
389 // Hover Height will override MoveTo target's Z 474 // Hover Height will override MoveTo target's Z
390 public override bool PIDHoverActive { 475 public override bool PIDHoverActive {
391 set { _useHoverPID = value; } 476 set { _useHoverPID = value; }
392 } 477 }
393 public override float PIDHoverHeight { 478 public override float PIDHoverHeight {
394 set { _PIDHoverHeight = value; } 479 set { _PIDHoverHeight = value; }
395 } 480 }
396 public override PIDHoverType PIDHoverType { 481 public override PIDHoverType PIDHoverType {
397 set { _PIDHoverType = value; } 482 set { _PIDHoverType = value; }
398 } 483 }
399 public override float PIDHoverTau { 484 public override float PIDHoverTau {
400 set { _PIDHoverTao = value; } 485 set { _PIDHoverTao = value; }
401 } 486 }
402 487
403 // For RotLookAt 488 // For RotLookAt
404 public override Quaternion APIDTarget { set { return; } } 489 public override OMV.Quaternion APIDTarget { set { return; } }
405 public override bool APIDActive { set { return; } } 490 public override bool APIDActive { set { return; } }
406 public override float APIDStrength { set { return; } } 491 public override float APIDStrength { set { return; } }
407 public override float APIDDamping { set { return; } } 492 public override float APIDDamping { set { return; } }
408 493
409 public override void AddForce(Vector3 force, bool pushforce) { 494 public override void AddForce(OMV.Vector3 force, bool pushforce) {
410 if (force.IsFinite()) 495 if (force.IsFinite())
411 { 496 {
412 _force.X += force.X; 497 _force.X += force.X;
413 _force.Y += force.Y; 498 _force.Y += force.Y;
414 _force.Z += force.Z; 499 _force.Z += force.Z;
415 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 500 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
416 _scene.TaintedObject("BSCharacter.AddForce", delegate() 501 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
417 { 502 {
418 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 503 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
419 BulletSimAPI.AddObjectForce2(Body.Ptr, _force); 504 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
420 }); 505 });
421 } 506 }
422 else 507 else
@@ -426,37 +511,19 @@ public class BSCharacter : PhysicsActor
426 //m_lastUpdateSent = false; 511 //m_lastUpdateSent = false;
427 } 512 }
428 513
429 public override void AddAngularForce(Vector3 force, bool pushforce) { 514 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
430 } 515 }
431 public override void SetMomentum(Vector3 momentum) { 516 public override void SetMomentum(OMV.Vector3 momentum) {
432 } 517 }
433 518
434 // Turn on collision events at a rate no faster than one every the given milliseconds 519 private void ComputeAvatarScale(OMV.Vector3 size)
435 public override void SubscribeEvents(int ms) { 520 {
436 _subscribedEventsMs = ms; 521 _scale.X = PhysicsScene.Params.avatarCapsuleRadius;
437 if (ms > 0) 522 _scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
438 {
439 // make sure first collision happens
440 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
441 523
442 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() 524 // The 1.15 came from ODE but it seems to cause the avatar to float off the ground
443 { 525 // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
444 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 526 _scale.Z = (_size.Z) - (_scale.X + _scale.Y);
445 });
446 }
447 }
448 // Stop collision events
449 public override void UnSubscribeEvents() {
450 _subscribedEventsMs = 0;
451 // Avatars get all their collision events
452 // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
453 // {
454 // BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
455 // });
456 }
457 // Return 'true' if someone has subscribed to events
458 public override bool SubscribedEvents() {
459 return (_subscribedEventsMs > 0);
460 } 527 }
461 528
462 // set _avatarVolume and _mass based on capsule size, _density and _scale 529 // set _avatarVolume and _mass based on capsule size, _density and _scale
@@ -473,82 +540,26 @@ public class BSCharacter : PhysicsActor
473 * Math.Min(_scale.X, _scale.Y) 540 * Math.Min(_scale.X, _scale.Y)
474 * _scale.Y // plus the volume of the capsule end caps 541 * _scale.Y // plus the volume of the capsule end caps
475 ); 542 );
476 _mass = _density * _avatarVolume; 543 _mass = _avatarDensity * _avatarVolume;
477 } 544 }
478 545
479 // The physics engine says that properties have updated. Update same and inform 546 // The physics engine says that properties have updated. Update same and inform
480 // the world that things have changed. 547 // the world that things have changed.
481 public void UpdateProperties(EntityProperties entprop) 548 public override void UpdateProperties(EntityProperties entprop)
482 { 549 {
483 _position = entprop.Position; 550 _position = entprop.Position;
484 _orientation = entprop.Rotation; 551 _orientation = entprop.Rotation;
485 _velocity = entprop.Velocity; 552 _velocity = entprop.Velocity;
486 _acceleration = entprop.Acceleration; 553 _acceleration = entprop.Acceleration;
487 _rotationalVelocity = entprop.RotationalVelocity; 554 _rotationalVelocity = entprop.RotationalVelocity;
555 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
556 PositionSanityCheck2(true);
557
488 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 558 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
489 // base.RequestPhysicsterseUpdate(); 559 // base.RequestPhysicsterseUpdate();
490 560
491 /*
492 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 561 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
493 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 562 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
494 entprop.Acceleration, entprop.RotationalVelocity);
495 */
496 }
497
498 // Called by the scene when a collision with this object is reported
499 // The collision, if it should be reported to the character, is placed in a collection
500 // that will later be sent to the simulator when SendCollisions() is called.
501 CollisionEventUpdate collisionCollection = null;
502 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
503 {
504 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
505
506 // The following makes IsColliding() and IsCollidingGround() work
507 _collidingStep = _scene.SimulationStep;
508 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
509 {
510 _collidingGroundStep = _scene.SimulationStep;
511 }
512 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
513
514 // throttle collisions to the rate specified in the subscription
515 if (_subscribedEventsMs != 0) {
516 int nowTime = _scene.SimulationNowTime;
517 if (nowTime >= _nextCollisionOkTime) {
518 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
519
520 if (collisionCollection == null)
521 collisionCollection = new CollisionEventUpdate();
522 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
523 }
524 }
525 }
526
527 public void SendCollisions()
528 {
529 /*
530 if (collisionCollection != null && collisionCollection.Count > 0)
531 {
532 base.SendCollisionUpdate(collisionCollection);
533 collisionCollection = null;
534 }
535 */
536 // Kludge to make a collision call even if there are no collisions.
537 // This causes the avatar animation to get updated.
538 if (collisionCollection == null)
539 collisionCollection = new CollisionEventUpdate();
540 base.SendCollisionUpdate(collisionCollection);
541 // If there were any collisions in the collection, make sure we don't use the
542 // same instance next time.
543 if (collisionCollection.Count > 0)
544 collisionCollection = null;
545 // End kludge
546 }
547
548 // Invoke the detailed logger and output something if it's enabled.
549 private void DetailLog(string msg, params Object[] args)
550 {
551 Scene.PhysicsLogging.Write(msg, args);
552 } 563 }
553} 564}
554} 565}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 25084d8..a20be3a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -48,22 +48,31 @@ public abstract class BSConstraint : IDisposable
48 { 48 {
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
51 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
54 m_constraint.Ptr = System.IntPtr.Zero;
55 m_enabled = false; 51 m_enabled = false;
52 if (m_constraint.ptr != IntPtr.Zero)
53 {
54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"),
59 success);
60 m_constraint.ptr = System.IntPtr.Zero;
61 }
56 } 62 }
57 } 63 }
58 64
59 public BulletBody Body1 { get { return m_body1; } } 65 public BulletBody Body1 { get { return m_body1; } }
60 public BulletBody Body2 { get { return m_body2; } } 66 public BulletBody Body2 { get { return m_body2; } }
67 public BulletConstraint Constraint { get { return m_constraint; } }
68 public abstract ConstraintType Type { get; }
69
61 70
62 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 71 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
63 { 72 {
64 bool ret = false; 73 bool ret = false;
65 if (m_enabled) 74 if (m_enabled)
66 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); 75 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
67 return ret; 76 return ret;
68 } 77 }
69 78
@@ -71,7 +80,18 @@ public abstract class BSConstraint : IDisposable
71 { 80 {
72 bool ret = false; 81 bool ret = false;
73 if (m_enabled) 82 if (m_enabled)
74 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); 83 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
84 return ret;
85 }
86
87 public virtual bool SetSolverIterations(float cnt)
88 {
89 bool ret = false;
90 if (m_enabled)
91 {
92 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
93 ret = true;
94 }
75 return ret; 95 return ret;
76 } 96 }
77 97
@@ -81,7 +101,7 @@ public abstract class BSConstraint : IDisposable
81 if (m_enabled) 101 if (m_enabled)
82 { 102 {
83 // Recompute the internal transforms 103 // Recompute the internal transforms
84 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); 104 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
85 ret = true; 105 ret = true;
86 } 106 }
87 return ret; 107 return ret;
@@ -97,13 +117,14 @@ public abstract class BSConstraint : IDisposable
97 ret = CalculateTransforms(); 117 ret = CalculateTransforms();
98 if (ret) 118 if (ret)
99 { 119 {
100 // m_world.scene.PhysicsLogging.Write("{0},BSConstraint.RecomputeConstraintVariables,taint,enabling,A={1},B={2}", 120 // Setting an object's mass to zero (making it static like when it's selected)
101 // BSScene.DetailLogZero, Body1.ID, Body2.ID); 121 // automatically disables the constraints.
102 BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); 122 // If the link is enabled, be sure to set the constraint itself to enabled.
123 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
103 } 124 }
104 else 125 else
105 { 126 {
106 m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 127 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
107 } 128 }
108 } 129 }
109 return ret; 130 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5a9f135..56342b8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -54,17 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public class BSDynamics
56 { 56 {
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private BSScene PhysicsScene { get; set; }
58 // every 100th frame 58 // the prim this dynamic controller belongs to
59 59 private BSPrim Prim { get; set; }
60 private BSPrim m_prim; // the prim this dynamic controller belongs to
61 60
62 // Vehicle properties 61 // Vehicle properties
63 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind 62 public Vehicle Type { get; set; }
64 public Vehicle Type 63
65 {
66 get { return m_type; }
67 }
68 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier 64 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
69 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: 65 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
70 // HOVER_TERRAIN_ONLY 66 // HOVER_TERRAIN_ONLY
@@ -74,13 +70,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
74 // HOVER_UP_ONLY 70 // HOVER_UP_ONLY
75 // LIMIT_MOTOR_UP 71 // LIMIT_MOTOR_UP
76 // LIMIT_ROLL_ONLY 72 // LIMIT_ROLL_ONLY
77 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
78 private Vector3 m_BlockingEndPoint = Vector3.Zero; 73 private Vector3 m_BlockingEndPoint = Vector3.Zero;
79 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 74 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
80 // Linear properties 75 // Linear properties
81 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 76 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
82 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
83 private Vector3 m_dir = Vector3.Zero; // velocity applied to body 78 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
84 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 79 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
85 private float m_linearMotorDecayTimescale = 0; 80 private float m_linearMotorDecayTimescale = 0;
86 private float m_linearMotorTimescale = 0; 81 private float m_linearMotorTimescale = 0;
@@ -97,7 +92,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
97 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 92 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
98 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
99 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 94 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
100 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
101 96
102 //Deflection properties 97 //Deflection properties
103 // private float m_angularDeflectionEfficiency = 0; 98 // private float m_angularDeflectionEfficiency = 0;
@@ -124,86 +119,74 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 private float m_verticalAttractionEfficiency = 1.0f; // damped 119 private float m_verticalAttractionEfficiency = 1.0f; // damped
125 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 120 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
126 121
127 public BSDynamics(BSPrim myPrim) 122 public BSDynamics(BSScene myScene, BSPrim myPrim)
123 {
124 PhysicsScene = myScene;
125 Prim = myPrim;
126 Type = Vehicle.TYPE_NONE;
127 }
128
129 // Return 'true' if this vehicle is doing vehicle things
130 public bool IsActive
128 { 131 {
129 m_prim = myPrim; 132 get { return Type != Vehicle.TYPE_NONE; }
130 m_type = Vehicle.TYPE_NONE;
131 } 133 }
132 134
133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) 135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
134 { 136 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 137 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
136 switch (pParam) 138 switch (pParam)
137 { 139 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
139 if (pValue < 0.01f) pValue = 0.01f; 141 // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
140 // m_angularDeflectionEfficiency = pValue;
141 break; 142 break;
142 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
143 if (pValue < 0.01f) pValue = 0.01f; 144 // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
144 // m_angularDeflectionTimescale = pValue;
145 break; 145 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 if (pValue < 0.01f) pValue = 0.01f; 147 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
148 m_angularMotorDecayTimescale = pValue;
149 break; 148 break;
150 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 149 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
151 if (pValue < 0.01f) pValue = 0.01f; 150 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
152 m_angularMotorTimescale = pValue;
153 break; 151 break;
154 case Vehicle.BANKING_EFFICIENCY: 152 case Vehicle.BANKING_EFFICIENCY:
155 if (pValue < 0.01f) pValue = 0.01f; 153 // m_bankingEfficiency = Math.Max(pValue, 0.01f);
156 // m_bankingEfficiency = pValue;
157 break; 154 break;
158 case Vehicle.BANKING_MIX: 155 case Vehicle.BANKING_MIX:
159 if (pValue < 0.01f) pValue = 0.01f; 156 // m_bankingMix = Math.Max(pValue, 0.01f);
160 // m_bankingMix = pValue;
161 break; 157 break;
162 case Vehicle.BANKING_TIMESCALE: 158 case Vehicle.BANKING_TIMESCALE:
163 if (pValue < 0.01f) pValue = 0.01f; 159 // m_bankingTimescale = Math.Max(pValue, 0.01f);
164 // m_bankingTimescale = pValue;
165 break; 160 break;
166 case Vehicle.BUOYANCY: 161 case Vehicle.BUOYANCY:
167 if (pValue < -1f) pValue = -1f; 162 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
168 if (pValue > 1f) pValue = 1f;
169 m_VehicleBuoyancy = pValue;
170 break; 163 break;
171// case Vehicle.HOVER_EFFICIENCY: 164// case Vehicle.HOVER_EFFICIENCY:
172// if (pValue < 0f) pValue = 0f; 165// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
173// if (pValue > 1f) pValue = 1f;
174// m_VhoverEfficiency = pValue;
175// break; 166// break;
176 case Vehicle.HOVER_HEIGHT: 167 case Vehicle.HOVER_HEIGHT:
177 m_VhoverHeight = pValue; 168 m_VhoverHeight = pValue;
178 break; 169 break;
179 case Vehicle.HOVER_TIMESCALE: 170 case Vehicle.HOVER_TIMESCALE:
180 if (pValue < 0.01f) pValue = 0.01f; 171 m_VhoverTimescale = Math.Max(pValue, 0.01f);
181 m_VhoverTimescale = pValue;
182 break; 172 break;
183 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 173 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
184 if (pValue < 0.01f) pValue = 0.01f; 174 // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
185 // m_linearDeflectionEfficiency = pValue;
186 break; 175 break;
187 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 176 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
188 if (pValue < 0.01f) pValue = 0.01f; 177 // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
189 // m_linearDeflectionTimescale = pValue;
190 break; 178 break;
191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 179 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
192 if (pValue < 0.01f) pValue = 0.01f; 180 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
193 m_linearMotorDecayTimescale = pValue;
194 break; 181 break;
195 case Vehicle.LINEAR_MOTOR_TIMESCALE: 182 case Vehicle.LINEAR_MOTOR_TIMESCALE:
196 if (pValue < 0.01f) pValue = 0.01f; 183 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
197 m_linearMotorTimescale = pValue;
198 break; 184 break;
199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 185 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
200 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable 186 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
201 if (pValue > 1.0f) pValue = 1.0f;
202 m_verticalAttractionEfficiency = pValue;
203 break; 187 break;
204 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 188 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
205 if (pValue < 0.01f) pValue = 0.01f; 189 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
206 m_verticalAttractionTimescale = pValue;
207 break; 190 break;
208 191
209 // These are vector properties but the engine lets you use a single float value to 192 // These are vector properties but the engine lets you use a single float value to
@@ -229,9 +212,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
229 } 212 }
230 }//end ProcessFloatVehicleParam 213 }//end ProcessFloatVehicleParam
231 214
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep) 215 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
233 { 216 {
234 DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 217 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
235 switch (pParam) 218 switch (pParam)
236 { 219 {
237 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 220 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -266,7 +249,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
266 249
267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 250 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
268 { 251 {
269 DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 252 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
270 switch (pParam) 253 switch (pParam)
271 { 254 {
272 case Vehicle.REFERENCE_FRAME: 255 case Vehicle.REFERENCE_FRAME:
@@ -280,166 +263,29 @@ namespace OpenSim.Region.Physics.BulletSPlugin
280 263
281 internal void ProcessVehicleFlags(int pParam, bool remove) 264 internal void ProcessVehicleFlags(int pParam, bool remove)
282 { 265 {
283 DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); 266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
267 VehicleFlag parm = (VehicleFlag)pParam;
284 if (remove) 268 if (remove)
285 { 269 {
286 if (pParam == -1) 270 if (pParam == -1)
287 { 271 {
288 m_flags = (VehicleFlag)0; 272 m_flags = (VehicleFlag)0;
289 m_Hoverflags = (VehicleFlag)0;
290 return;
291 }
292 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
293 {
294 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
295 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
296 }
297 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
298 {
299 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
300 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
301 }
302 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
303 {
304 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
305 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
306 }
307 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
308 {
309 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
310 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
311 }
312 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
313 {
314 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
315 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
316 }
317 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
318 {
319 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
320 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
321 }
322 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
323 {
324 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
325 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
326 }
327 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
328 {
329 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
330 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
331 } 273 }
332 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) 274 else
333 {
334 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
335 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
336 }
337 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
338 {
339 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
340 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
341 }
342 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
343 {
344 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
345 m_flags &= ~(VehicleFlag.NO_X);
346 }
347 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
348 {
349 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
350 m_flags &= ~(VehicleFlag.NO_Y);
351 }
352 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
353 {
354 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
355 m_flags &= ~(VehicleFlag.NO_Z);
356 }
357 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
358 {
359 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
360 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
361 }
362 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
363 {
364 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
365 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
366 }
367 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
368 { 275 {
369 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) 276 m_flags &= ~parm;
370 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
371 } 277 }
372 } 278 }
373 else 279 else {
374 { 280 m_flags |= parm;
375 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
376 {
377 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
378 }
379 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
380 {
381 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
382 }
383 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
384 {
385 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
386 }
387 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
388 {
389 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
390 }
391 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
392 {
393 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
394 }
395 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
396 {
397 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
398 }
399 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
400 {
401 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
402 }
403 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
404 {
405 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
406 }
407 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
408 {
409 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
410 }
411 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
412 {
413 m_flags |= (VehicleFlag.NO_X);
414 }
415 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
416 {
417 m_flags |= (VehicleFlag.NO_Y);
418 }
419 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
420 {
421 m_flags |= (VehicleFlag.NO_Z);
422 }
423 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
424 {
425 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
426 }
427 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
428 {
429 m_flags |= (VehicleFlag.NO_DEFLECTION);
430 }
431 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
432 {
433 m_flags |= (VehicleFlag.LOCK_ROTATION);
434 }
435 } 281 }
436 }//end ProcessVehicleFlags 282 }//end ProcessVehicleFlags
437 283
438 internal void ProcessTypeChange(Vehicle pType) 284 internal void ProcessTypeChange(Vehicle pType)
439 { 285 {
440 DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); 286 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
441 // Set Defaults For Type 287 // Set Defaults For Type
442 m_type = pType; 288 Type = pType;
443 switch (pType) 289 switch (pType)
444 { 290 {
445 case Vehicle.TYPE_NONE: 291 case Vehicle.TYPE_NONE:
@@ -478,10 +324,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
478 // m_bankingMix = 1; 324 // m_bankingMix = 1;
479 // m_bankingTimescale = 10; 325 // m_bankingTimescale = 10;
480 // m_referenceFrame = Quaternion.Identity; 326 // m_referenceFrame = Quaternion.Identity;
481 m_Hoverflags &= 327 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
328 m_flags &=
482 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 329 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
483 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 330 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
484 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
485 break; 331 break;
486 case Vehicle.TYPE_CAR: 332 case Vehicle.TYPE_CAR:
487 m_linearFrictionTimescale = new Vector3(100, 2, 1000); 333 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
@@ -506,10 +352,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
506 // m_bankingMix = 1; 352 // m_bankingMix = 1;
507 // m_bankingTimescale = 1; 353 // m_bankingTimescale = 1;
508 // m_referenceFrame = Quaternion.Identity; 354 // m_referenceFrame = Quaternion.Identity;
509 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
510 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | 356 | VehicleFlag.LIMIT_ROLL_ONLY
511 VehicleFlag.LIMIT_MOTOR_UP); 357 | VehicleFlag.LIMIT_MOTOR_UP);
512 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
359 m_flags |= (VehicleFlag.HOVER_UP_ONLY);
513 break; 360 break;
514 case Vehicle.TYPE_BOAT: 361 case Vehicle.TYPE_BOAT:
515 m_linearFrictionTimescale = new Vector3(10, 3, 2); 362 m_linearFrictionTimescale = new Vector3(10, 3, 2);
@@ -534,12 +381,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
534 // m_bankingMix = 0.8f; 381 // m_bankingMix = 0.8f;
535 // m_bankingTimescale = 1; 382 // m_bankingTimescale = 1;
536 // m_referenceFrame = Quaternion.Identity; 383 // m_referenceFrame = Quaternion.Identity;
537 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
538 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 385 | VehicleFlag.HOVER_GLOBAL_HEIGHT
539 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); 386 | VehicleFlag.LIMIT_ROLL_ONLY
540 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 387 | VehicleFlag.HOVER_UP_ONLY);
541 VehicleFlag.LIMIT_MOTOR_UP); 388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
542 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); 389 | VehicleFlag.LIMIT_MOTOR_UP
390 | VehicleFlag.HOVER_WATER_ONLY);
543 break; 391 break;
544 case Vehicle.TYPE_AIRPLANE: 392 case Vehicle.TYPE_AIRPLANE:
545 m_linearFrictionTimescale = new Vector3(200, 10, 5); 393 m_linearFrictionTimescale = new Vector3(200, 10, 5);
@@ -564,9 +412,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
564 // m_bankingMix = 0.7f; 412 // m_bankingMix = 0.7f;
565 // m_bankingTimescale = 2; 413 // m_bankingTimescale = 2;
566 // m_referenceFrame = Quaternion.Identity; 414 // m_referenceFrame = Quaternion.Identity;
567 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 415 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
568 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 416 | VehicleFlag.HOVER_TERRAIN_ONLY
569 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 417 | VehicleFlag.HOVER_GLOBAL_HEIGHT
418 | VehicleFlag.HOVER_UP_ONLY
419 | VehicleFlag.NO_DEFLECTION_UP
420 | VehicleFlag.LIMIT_MOTOR_UP);
570 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 421 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
571 break; 422 break;
572 case Vehicle.TYPE_BALLOON: 423 case Vehicle.TYPE_BALLOON:
@@ -592,50 +443,66 @@ namespace OpenSim.Region.Physics.BulletSPlugin
592 // m_bankingMix = 0.7f; 443 // m_bankingMix = 0.7f;
593 // m_bankingTimescale = 5; 444 // m_bankingTimescale = 5;
594 // m_referenceFrame = Quaternion.Identity; 445 // m_referenceFrame = Quaternion.Identity;
595 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 446 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
596 VehicleFlag.HOVER_UP_ONLY); 447 | VehicleFlag.HOVER_TERRAIN_ONLY
597 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 448 | VehicleFlag.HOVER_UP_ONLY
598 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 449 | VehicleFlag.NO_DEFLECTION_UP
599 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); 450 | VehicleFlag.LIMIT_MOTOR_UP);
451 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
452 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
600 break; 453 break;
601 } 454 }
602 }//end SetDefaultsForType 455 }//end SetDefaultsForType
603 456
604 internal void Step(float pTimestep) 457 // Some of the properties of this prim may have changed.
458 // Do any updating needed for a vehicle
459 public void Refresh()
605 { 460 {
606 if (m_type == Vehicle.TYPE_NONE) return; 461 if (!IsActive)
462 return;
463
464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
469 }
607 470
608 frcount++; // used to limit debug comment output 471 // One step of the vehicle properties for the next 'pTimestep' seconds.
609 if (frcount > 100) 472 internal void Step(float pTimestep)
610 frcount = 0; 473 {
474 if (!IsActive) return;
611 475
612 MoveLinear(pTimestep); 476 MoveLinear(pTimestep);
613 MoveAngular(pTimestep); 477 MoveAngular(pTimestep);
614 LimitRotation(pTimestep); 478 LimitRotation(pTimestep);
615 479
616 DetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 480 // remember the position so next step we can limit absolute movement effects
617 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); 481 m_lastPositionVector = Prim.ForcePosition;
482
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
618 }// end Step 485 }// end Step
619 486
487 // Apply the effect of the linear motor.
488 // Also does hover and float.
620 private void MoveLinear(float pTimestep) 489 private void MoveLinear(float pTimestep)
621 { 490 {
622 // requested m_linearMotorDirection is significant 491 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) 492 // m_lastLinearVelocityVector is the speed we are moving in that direction
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f) 493 if (m_linearMotorDirection.LengthSquared() > 0.001f)
625 { 494 {
626 Vector3 origDir = m_linearMotorDirection; 495 Vector3 origDir = m_linearMotorDirection;
627 Vector3 origVel = m_lastLinearVelocityVector; 496 Vector3 origVel = m_lastLinearVelocityVector;
628 497
629 // add drive to body 498 // add drive to body
630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 499 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep);
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); 500 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep);
632 // lastLinearVelocityVector is the current body velocity vector? 501 // lastLinearVelocityVector is the current body velocity vector
633 // RA: Not sure what the *10 is for. A correction for pTimestep? 502 // RA: Not sure what the *10 is for. A correction for pTimestep?
634 // m_lastLinearVelocityVector += (addAmount*10); 503 // m_lastLinearVelocityVector += (addAmount*10);
635 m_lastLinearVelocityVector += addAmount; 504 m_lastLinearVelocityVector += addAmount;
636 505
637 // This will work temporarily, but we really need to compare speed on an axis
638 // KF: Limit body velocity to applied velocity?
639 // Limit the velocity vector to less than the last set linear motor direction 506 // Limit the velocity vector to less than the last set linear motor direction
640 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 507 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 508 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
@@ -644,124 +511,87 @@ namespace OpenSim.Region.Physics.BulletSPlugin
644 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 511 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
645 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 512 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
646 513
514 /*
647 // decay applied velocity 515 // decay applied velocity
648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); 516 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep);
517 // (RA: do not know where the 0.5f comes from)
649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 518 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
650
651 /*
652 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
653 m_lastLinearVelocityVector += addAmount;
654
655 float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale);
656 m_linearMotorDirection *= decayfraction;
657
658 */ 519 */
520 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
521 m_linearMotorDirection *= keepfraction;
659 522
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", 523 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
661 m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector); 524 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
662 } 525 }
663 else 526 else
664 { 527 {
665 // if what remains of applied is small, zero it. 528 // if what remains of direction is very small, zero it.
666 // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
667 // m_lastLinearVelocityVector = Vector3.Zero;
668 m_linearMotorDirection = Vector3.Zero; 529 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero; 530 m_lastLinearVelocityVector = Vector3.Zero;
531 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
670 } 532 }
671 533
672 // convert requested object velocity to world-referenced vector 534 // convert requested object velocity to object relative vector
673 Quaternion rotq = m_prim.Orientation; 535 Quaternion rotq = Prim.ForceOrientation;
674 m_dir = m_lastLinearVelocityVector * rotq; 536 m_newVelocity = m_lastLinearVelocityVector * rotq;
675 537
676 // Add the various forces into m_dir which will be our new direction vector (velocity) 538 // Add the various forces into m_dir which will be our new direction vector (velocity)
677 539
678 // add Gravity and Buoyancy 540 // add Gravity and Buoyancy
679 // KF: So far I have found no good method to combine a script-requested
680 // .Z velocity and gravity. Therefore only 0g will used script-requested
681 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
682 Vector3 grav = Vector3.Zero;
683 // There is some gravity, make a gravity force vector that is applied after object velocity. 541 // There is some gravity, make a gravity force vector that is applied after object velocity.
684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); 543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
544
545 /*
546 * RA: Not sure why one would do this
686 // Preserve the current Z velocity 547 // Preserve the current Z velocity
687 Vector3 vel_now = m_prim.Velocity; 548 Vector3 vel_now = m_prim.Velocity;
688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 549 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
550 */
689 551
690 Vector3 pos = m_prim.Position; 552 Vector3 pos = Prim.ForcePosition;
691 Vector3 posChange = pos;
692// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); 553// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
693 double Zchange = Math.Abs(posChange.Z);
694 if (m_BlockingEndPoint != Vector3.Zero)
695 {
696 bool changed = false;
697 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
698 {
699 pos.X -= posChange.X + 1;
700 changed = true;
701 }
702 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
703 {
704 pos.Y -= posChange.Y + 1;
705 changed = true;
706 }
707 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
708 {
709 pos.Z -= posChange.Z + 1;
710 changed = true;
711 }
712 if (pos.X <= 0)
713 {
714 pos.X += posChange.X + 1;
715 changed = true;
716 }
717 if (pos.Y <= 0)
718 {
719 pos.Y += posChange.Y + 1;
720 changed = true;
721 }
722 if (changed)
723 {
724 m_prim.Position = pos;
725 DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
726 m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
727 }
728 }
729 554
730 // If below the terrain, move us above the ground a little. 555 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) 556 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
557 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
558 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
559 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
560 // if (rotatedSize.Z < terrainHeight)
561 if (pos.Z < terrainHeight)
732 { 562 {
733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; 563 pos.Z = terrainHeight + 2;
734 m_prim.Position = pos; 564 Prim.ForcePosition = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); 565 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
736 } 566 }
737 567
738 // Check if hovering 568 // Check if hovering
739 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 569 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
740 { 570 {
741 // We should hover, get the target height 571 // We should hover, get the target height
742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 572 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
743 { 573 {
744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; 574 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
745 } 575 }
746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 576 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
747 { 577 {
748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 578 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight;
749 } 579 }
750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 580 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
751 { 581 {
752 m_VhoverTargetHeight = m_VhoverHeight; 582 m_VhoverTargetHeight = m_VhoverHeight;
753 } 583 }
754 584
755 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) 585 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
756 { 586 {
757 // If body is aready heigher, use its height as target height 587 // If body is aready heigher, use its height as target height
758 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 588 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
759 } 589 }
760 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 590 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
761 { 591 {
762 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 592 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
763 { 593 {
764 m_prim.Position = pos; 594 Prim.ForcePosition = pos;
765 } 595 }
766 } 596 }
767 else 597 else
@@ -770,85 +600,99 @@ namespace OpenSim.Region.Physics.BulletSPlugin
770 // Replace Vertical speed with correction figure if significant 600 // Replace Vertical speed with correction figure if significant
771 if (Math.Abs(herr0) > 0.01f) 601 if (Math.Abs(herr0) > 0.01f)
772 { 602 {
773 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 603 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
774 //KF: m_VhoverEfficiency is not yet implemented 604 //KF: m_VhoverEfficiency is not yet implemented
775 } 605 }
776 else 606 else
777 { 607 {
778 m_dir.Z = 0f; 608 m_newVelocity.Z = 0f;
779 } 609 }
780 } 610 }
781 611
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); 612 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
613 }
783 614
784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped 615 Vector3 posChange = pos - m_lastPositionVector;
785// m_VhoverTimescale = 0f; // time to acheive height 616 if (m_BlockingEndPoint != Vector3.Zero)
786// pTimestep is time since last frame,in secs 617 {
618 bool changed = false;
619 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
620 {
621 pos.X -= posChange.X + 1;
622 changed = true;
623 }
624 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
625 {
626 pos.Y -= posChange.Y + 1;
627 changed = true;
628 }
629 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
630 {
631 pos.Z -= posChange.Z + 1;
632 changed = true;
633 }
634 if (pos.X <= 0)
635 {
636 pos.X += posChange.X + 1;
637 changed = true;
638 }
639 if (pos.Y <= 0)
640 {
641 pos.Y += posChange.Y + 1;
642 changed = true;
643 }
644 if (changed)
645 {
646 Prim.ForcePosition = pos;
647 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
648 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
649 }
787 } 650 }
788 651
652 // Limit absolute vertical change
653 float Zchange = Math.Abs(posChange.Z);
789 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 654 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
790 { 655 {
791 //Start Experimental Values
792 if (Zchange > .3) 656 if (Zchange > .3)
793 {
794 grav.Z = (float)(grav.Z * 3); 657 grav.Z = (float)(grav.Z * 3);
795 }
796 if (Zchange > .15) 658 if (Zchange > .15)
797 {
798 grav.Z = (float)(grav.Z * 2); 659 grav.Z = (float)(grav.Z * 2);
799 }
800 if (Zchange > .75) 660 if (Zchange > .75)
801 {
802 grav.Z = (float)(grav.Z * 1.5); 661 grav.Z = (float)(grav.Z * 1.5);
803 }
804 if (Zchange > .05) 662 if (Zchange > .05)
805 {
806 grav.Z = (float)(grav.Z * 1.25); 663 grav.Z = (float)(grav.Z * 1.25);
807 }
808 if (Zchange > .025) 664 if (Zchange > .025)
809 {
810 grav.Z = (float)(grav.Z * 1.125); 665 grav.Z = (float)(grav.Z * 1.125);
811 } 666 float postemp = (pos.Z - terrainHeight);
812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
813 float postemp = (pos.Z - terraintemp);
814 if (postemp > 2.5f) 667 if (postemp > 2.5f)
815 {
816 grav.Z = (float)(grav.Z * 1.037125); 668 grav.Z = (float)(grav.Z * 1.037125);
817 } 669 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
818 DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
819 //End Experimental Values
820 } 670 }
671
672 // If not changing some axis, reduce out velocity
821 if ((m_flags & (VehicleFlag.NO_X)) != 0) 673 if ((m_flags & (VehicleFlag.NO_X)) != 0)
822 { 674 m_newVelocity.X = 0;
823 m_dir.X = 0;
824 }
825 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 675 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
826 { 676 m_newVelocity.Y = 0;
827 m_dir.Y = 0;
828 }
829 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 677 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
830 { 678 m_newVelocity.Z = 0;
831 m_dir.Z = 0;
832 }
833
834 m_lastPositionVector = m_prim.Position;
835 679
836 // Apply velocity 680 // Apply velocity
837 m_prim.Velocity = m_dir; 681 Prim.ForceVelocity = m_newVelocity;
838 // apply gravity force 682 // apply gravity force
839 // Why is this set here? The physics engine already does gravity. 683 // Why is this set here? The physics engine already does gravity.
840 // m_prim.AddForce(grav, false); 684 Prim.AddForce(grav, false, true);
841 // m_prim.Force = grav;
842 685
843 // Apply friction 686 // Apply friction
844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); 687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
845 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; 688 m_lastLinearVelocityVector *= keepFraction;
846 689
847 DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", 690 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
848 m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); 691 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
849 692
850 } // end MoveLinear() 693 } // end MoveLinear()
851 694
695 // Apply the effect of the angular motor.
852 private void MoveAngular(float pTimestep) 696 private void MoveAngular(float pTimestep)
853 { 697 {
854 // m_angularMotorDirection // angular velocity requested by LSL motor 698 // m_angularMotorDirection // angular velocity requested by LSL motor
@@ -860,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
860 // m_lastAngularVelocity // what was last applied to body 704 // m_lastAngularVelocity // what was last applied to body
861 705
862 // Get what the body is doing, this includes 'external' influences 706 // Get what the body is doing, this includes 'external' influences
863 Vector3 angularVelocity = m_prim.RotationalVelocity; 707 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
864 708
865 if (m_angularMotorApply > 0) 709 if (m_angularMotorApply > 0)
866 { 710 {
@@ -868,48 +712,58 @@ namespace OpenSim.Region.Physics.BulletSPlugin
868 // a newly set velocity, this routine steps the value from the previous 712 // a newly set velocity, this routine steps the value from the previous
869 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). 713 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
870 // There are m_angularMotorApply steps. 714 // There are m_angularMotorApply steps.
871 Vector3 origAngularVelocity = m_angularMotorVelocity; 715 Vector3 origVel = m_angularMotorVelocity;
716 Vector3 origDir = m_angularMotorDirection;
717
872 // ramp up to new value 718 // ramp up to new value
873 // current velocity += error / (time to get there / step interval) 719 // new velocity += error / ( time to get there / step interval)
874 // requested speed - last motor speed 720 // requested speed - last motor speed
875 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 721 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
876 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 722 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
877 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 723 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
878 724
879 DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}", 725 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}",
880 m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); 726 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
881 727
882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected 728 m_angularMotorApply--;
883 // velocity may still be acheived.
884 } 729 }
885 else 730 else
886 { 731 {
887 // No motor recently applied, keep the body velocity 732 // No motor recently applied, keep the body velocity
888 // and decay the velocity 733 // and decay the velocity
889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 734 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
735 if (m_angularMotorVelocity.LengthSquared() < 0.00001)
736 m_angularMotorVelocity = Vector3.Zero;
890 } // end motor section 737 } // end motor section
891 738
892 // Vertical attractor section 739 // Vertical attractor section
893 Vector3 vertattr = Vector3.Zero; 740 Vector3 vertattr = Vector3.Zero;
894 if (m_verticalAttractionTimescale < 300) 741 Vector3 deflection = Vector3.Zero;
742 Vector3 banking = Vector3.Zero;
743
744 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
895 { 745 {
896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 746 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
747 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
748
897 // get present body rotation 749 // get present body rotation
898 Quaternion rotq = m_prim.Orientation; 750 Quaternion rotq = Prim.ForceOrientation;
899 // make a vector pointing up 751 // vector pointing up
900 Vector3 verterr = Vector3.Zero; 752 Vector3 verterr = Vector3.Zero;
901 verterr.Z = 1.0f; 753 verterr.Z = 1.0f;
754
902 // rotate it to Body Angle 755 // rotate it to Body Angle
903 verterr = verterr * rotq; 756 verterr = verterr * rotq;
904 // 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. 757 // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
905 // 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 758 // 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
906 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 759 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
760
761 // Error is 0 (no error) to +/- 2 (max error)
907 if (verterr.Z < 0.0f) 762 if (verterr.Z < 0.0f)
908 { 763 {
909 verterr.X = 2.0f - verterr.X; 764 verterr.X = 2.0f - verterr.X;
910 verterr.Y = 2.0f - verterr.Y; 765 verterr.Y = 2.0f - verterr.Y;
911 } 766 }
912 // Error is 0 (no error) to +/- 2 (max error)
913 // scale it by VAservo 767 // scale it by VAservo
914 verterr = verterr * VAservo; 768 verterr = verterr * VAservo;
915 769
@@ -924,12 +778,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
924 vertattr.X += bounce * angularVelocity.X; 778 vertattr.X += bounce * angularVelocity.X;
925 vertattr.Y += bounce * angularVelocity.Y; 779 vertattr.Y += bounce * angularVelocity.Y;
926 780
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 781 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
928 m_prim.LocalID, verterr, bounce, vertattr); 782 Prim.LocalID, verterr, bounce, vertattr);
929 783
930 } // else vertical attractor is off 784 } // else vertical attractor is off
931 785
932 // m_lastVertAttractor = vertattr; 786 m_lastVertAttractor = vertattr;
933 787
934 // Bank section tba 788 // Bank section tba
935 789
@@ -937,18 +791,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
937 791
938 // Sum velocities 792 // Sum velocities
939 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
940 794
941 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
942 { 796 {
943 m_lastAngularVelocity.X = 0; 797 m_lastAngularVelocity.X = 0;
944 m_lastAngularVelocity.Y = 0; 798 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 799 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
946 } 800 }
947 801
948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 802 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
949 { 803 {
950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 804 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 805 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
952 } 806 }
953 807
954 // apply friction 808 // apply friction
@@ -956,14 +810,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
956 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
957 811
958 // Apply to the body 812 // Apply to the body
959 m_prim.RotationalVelocity = m_lastAngularVelocity; 813 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
960 814
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); 815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
962 } //end MoveAngular 816 } //end MoveAngular
963 817
964 internal void LimitRotation(float timestep) 818 internal void LimitRotation(float timestep)
965 { 819 {
966 Quaternion rotq = m_prim.Orientation; 820 Quaternion rotq = Prim.ForceOrientation;
967 Quaternion m_rot = rotq; 821 Quaternion m_rot = rotq;
968 bool changed = false; 822 bool changed = false;
969 if (m_RollreferenceFrame != Quaternion.Identity) 823 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -996,23 +850,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
996 m_rot.Y = 0; 850 m_rot.Y = 0;
997 changed = true; 851 changed = true;
998 } 852 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 853 if (changed)
1000 { 854 {
1001 m_rot.X = 0; 855 Prim.ForceOrientation = m_rot;
1002 m_rot.Y = 0; 856 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1003 changed = true;
1004 } 857 }
1005 if (changed)
1006 m_prim.Orientation = m_rot;
1007 858
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 } 859 }
1010 860
1011 // Invoke the detailed logger and output something if it's enabled. 861 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args) 862 private void VDetailLog(string msg, params Object[] args)
1013 { 863 {
1014 if (m_prim.Scene.VehicleLoggingEnabled) 864 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args); 865 Prim.PhysicsScene.DetailLog(msg, args);
1016 } 866 }
1017 } 867 }
1018} 868}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
index d68048b..7c8a215 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
@@ -1,55 +1,57 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35class BSHingeConstraint : BSConstraint
36{ 36{
37 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 Vector3 pivotInA, Vector3 pivotInB, 38
39 Vector3 axisInA, Vector3 axisInB, 39 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
40 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 40 Vector3 pivotInA, Vector3 pivotInB,
41 { 41 Vector3 axisInA, Vector3 axisInB,
42 m_world = world; 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 m_body1 = obj1; 43 {
44 m_body2 = obj2; 44 m_world = world;
45 m_constraint = new BulletConstraint( 45 m_body1 = obj1;
46 BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 46 m_body2 = obj2;
47 pivotInA, pivotInB, 47 m_constraint = new BulletConstraint(
48 axisInA, axisInB, 48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 49 pivotInA, pivotInB,
50 m_enabled = true; 50 axisInA, axisInB,
51 } 51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 52 m_enabled = true;
53} 53 }
54 54
55} 55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 087b9bb..43b1262 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -34,16 +34,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public class BSLinkset
36{ 36{
37 private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 private BSPrim m_linksetRoot; 39 public BSPhysObject LinksetRoot { get; protected set; }
40 public BSPrim LinksetRoot { get { return m_linksetRoot; } }
41 40
42 private BSScene m_physicsScene; 41 public BSScene PhysicsScene { get; private set; }
43 public BSScene PhysicsScene { get { return m_physicsScene; } }
44 42
45 // The children under the root in this linkset 43 static int m_nextLinksetID = 1;
46 private List<BSPrim> m_children; 44 public int LinksetID { get; private set; }
45
46 // The children under the root in this linkset.
47 // There are two lists of children: the current children at runtime
48 // and the children at taint-time. For instance, if you delink a
49 // child from the linkset, the child is removed from m_children
50 // but the constraint won't be removed until taint time.
51 // Two lists lets this track the 'current' children and
52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these
54 // two lists must be the same.
55 private HashSet<BSPhysObject> m_children;
56 private HashSet<BSPhysObject> m_taintChildren;
47 57
48 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
49 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -52,9 +62,9 @@ public class BSLinkset
52 62
53 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
54 private float m_mass; 64 private float m_mass;
55 public float LinksetMass 65 public float LinksetMass
56 { 66 {
57 get 67 get
58 { 68 {
59 m_mass = ComputeLinksetMass(); 69 m_mass = ComputeLinksetMass();
60 return m_mass; 70 return m_mass;
@@ -71,23 +81,31 @@ public class BSLinkset
71 get { return ComputeLinksetGeometricCenter(); } 81 get { return ComputeLinksetGeometricCenter(); }
72 } 82 }
73 83
74 public BSLinkset(BSScene scene, BSPrim parent) 84 public BSLinkset(BSScene scene, BSPhysObject parent)
75 { 85 {
76 // A simple linkset of one (no children) 86 // A simple linkset of one (no children)
77 m_physicsScene = scene; 87 LinksetID = m_nextLinksetID++;
78 m_linksetRoot = parent; 88 // We create LOTS of linksets.
79 m_children = new List<BSPrim>(); 89 if (m_nextLinksetID <= 0)
90 m_nextLinksetID = 1;
91 PhysicsScene = scene;
92 LinksetRoot = parent;
93 m_children = new HashSet<BSPhysObject>();
94 m_taintChildren = new HashSet<BSPhysObject>();
80 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
81 } 96 }
82 97
83 // Link to a linkset where the child knows the parent. 98 // Link to a linkset where the child knows the parent.
84 // Parent changing should not happen so do some sanity checking. 99 // Parent changing should not happen so do some sanity checking.
85 // We return the parent's linkset so the child can track its membership. 100 // We return the parent's linkset so the child can track its membership.
86 public BSLinkset AddMeToLinkset(BSPrim child) 101 // Called at runtime.
102 public BSLinkset AddMeToLinkset(BSPhysObject child)
87 { 103 {
88 lock (m_linksetActivityLock) 104 lock (m_linksetActivityLock)
89 { 105 {
90 AddChildToLinkset(child); 106 // Don't add the root to its own linkset
107 if (!IsRoot(child))
108 AddChildToLinkset(child);
91 } 109 }
92 return this; 110 return this;
93 } 111 }
@@ -95,26 +113,18 @@ public class BSLinkset
95 // Remove a child from a linkset. 113 // Remove a child from a linkset.
96 // Returns a new linkset for the child which is a linkset of one (just the 114 // Returns a new linkset for the child which is a linkset of one (just the
97 // orphened child). 115 // orphened child).
98 public BSLinkset RemoveMeFromLinkset(BSPrim child) 116 // Called at runtime.
117 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
99 { 118 {
100 lock (m_linksetActivityLock) 119 lock (m_linksetActivityLock)
101 { 120 {
102 if (IsRoot(child)) 121 if (IsRoot(child))
103 { 122 {
104 // if root of linkset, take the linkset apart 123 // Cannot remove the root from a linkset.
105 while (m_children.Count > 0) 124 return this;
106 {
107 // Note that we don't do a foreach because the remove routine
108 // takes it out of the list.
109 RemoveChildFromOtherLinkset(m_children[0]);
110 }
111 m_children.Clear(); // just to make sure
112 }
113 else
114 {
115 // Just removing a child from an existing linkset
116 RemoveChildFromLinkset(child);
117 } 125 }
126
127 RemoveChildFromLinkset(child);
118 } 128 }
119 129
120 // The child is down to a linkset of just itself 130 // The child is down to a linkset of just itself
@@ -122,9 +132,9 @@ public class BSLinkset
122 } 132 }
123 133
124 // Return 'true' if the passed object is the root object of this linkset 134 // Return 'true' if the passed object is the root object of this linkset
125 public bool IsRoot(BSPrim requestor) 135 public bool IsRoot(BSPhysObject requestor)
126 { 136 {
127 return (requestor.LocalID == m_linksetRoot.LocalID); 137 return (requestor.LocalID == LinksetRoot.LocalID);
128 } 138 }
129 139
130 public int NumberOfChildren { get { return m_children.Count; } } 140 public int NumberOfChildren { get { return m_children.Count; } }
@@ -133,12 +143,12 @@ public class BSLinkset
133 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 143 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
134 144
135 // Return 'true' if this child is in this linkset 145 // Return 'true' if this child is in this linkset
136 public bool HasChild(BSPrim child) 146 public bool HasChild(BSPhysObject child)
137 { 147 {
138 bool ret = false; 148 bool ret = false;
139 lock (m_linksetActivityLock) 149 lock (m_linksetActivityLock)
140 { 150 {
141 foreach (BSPrim bp in m_children) 151 foreach (BSPhysObject bp in m_children)
142 { 152 {
143 if (child.LocalID == bp.LocalID) 153 if (child.LocalID == bp.LocalID)
144 { 154 {
@@ -150,117 +160,204 @@ public class BSLinkset
150 return ret; 160 return ret;
151 } 161 }
152 162
153 private float ComputeLinksetMass() 163 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime)
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184
185 // The object is going dynamic (physical). Do any setup necessary
186 // for a dynamic linkset.
187 // Only the state of the passed object can be modified. The rest of the linkset
188 // has not yet been fully constructed.
189 // Return 'true' if any properties updated on the passed object.
190 // Called at taint-time!
191 public bool MakeDynamic(BSPhysObject child)
192 {
193 // What is done for each object in BSPrim is what we want.
194 return false;
195 }
196
197 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time!
201 public bool MakeStatic(BSPhysObject child)
202 {
203 // What is done for each object in BSPrim is what we want.
204 return false;
205 }
206
207 // If the software is handling the movement of all the objects in a linkset
208 // (like if one doesn't use constraints for static linksets), this is called
209 // when an update for the root of the linkset is received.
210 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject)
154 { 212 {
155 float mass = m_linksetRoot.MassRaw; 213 // The root local properties have been updated. Apply to the children if appropriate.
156 foreach (BSPrim bp in m_children) 214 if (IsRoot(physObject) && HasAnyChildren)
157 { 215 {
158 mass += bp.MassRaw; 216 if (!physObject.IsPhysical)
217 {
218 // TODO: implement software linkset update for static object linksets
219 }
159 } 220 }
160 return mass;
161 } 221 }
162 222
163 private OMV.Vector3 ComputeLinksetCenterOfMass() 223 // Routine used when rebuilding the body of the root of the linkset
224 // Destroy all the constraints have have been made to root.
225 // This is called when the root body is changing.
226 // Returns 'true' of something eas actually removed and would need restoring
227 // Called at taint-time!!
228 public bool RemoveBodyDependencies(BSPrim child)
164 { 229 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 230 bool ret = false;
166 float totalMass = m_linksetRoot.MassRaw;
167 231
168 lock (m_linksetActivityLock) 232 lock (m_linksetActivityLock)
169 { 233 {
170 foreach (BSPrim bp in m_children) 234 if (IsRoot(child))
171 { 235 {
172 com += bp.Position * bp.MassRaw; 236 // If the one with the dependency is root, must undo all children
173 totalMass += bp.MassRaw; 237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
239
240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
241 }
242 else
243 {
244 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
245 child.LocalID,
246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
247 child.LocalID, child.BSBody.ptr.ToString("X"));
248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
249 // Despite the function name, this removes any link to the specified object.
250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
174 } 251 }
175 if (totalMass != 0f)
176 com /= totalMass;
177 } 252 }
178 253 return ret;
179 return com;
180 } 254 }
181 255
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
257 // this routine will restore the removed constraints.
258 // Called at taint-time!!
259 public void RestoreBodyDependencies(BSPrim child)
183 { 260 {
184 OMV.Vector3 com = m_linksetRoot.Position;
185
186 lock (m_linksetActivityLock) 261 lock (m_linksetActivityLock)
187 { 262 {
188 foreach (BSPrim bp in m_children) 263 if (IsRoot(child))
189 { 264 {
190 com += bp.Position * bp.MassRaw; 265 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
267 foreach (BSPhysObject bpo in m_taintChildren)
268 {
269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
270 }
271 }
272 else
273 {
274 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
275 LinksetRoot.LocalID,
276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
277 child.LocalID, child.BSBody.ptr.ToString("X"));
278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
191 } 279 }
192 com /= (m_children.Count + 1);
193 } 280 }
194
195 return com;
196 } 281 }
197 282
198 // When physical properties are changed the linkset needs to recalculate 283 // ================================================================
199 // its internal properties. 284 // Below this point is internal magic
200 public void Refresh(BSPrim requestor) 285
286 private float ComputeLinksetMass()
201 { 287 {
202 // If there are no children, there aren't any constraints to recompute 288 float mass;
203 if (!HasAnyChildren) 289 lock (m_linksetActivityLock)
204 return; 290 {
291 mass = LinksetRoot.MassRaw;
292 foreach (BSPhysObject bp in m_taintChildren)
293 {
294 mass += bp.MassRaw;
295 }
296 }
297 return mass;
298 }
205 299
206 // Only the root does the recomputation 300 private OMV.Vector3 ComputeLinksetCenterOfMass()
207 if (IsRoot(requestor)) 301 {
302 OMV.Vector3 com;
303 lock (m_linksetActivityLock)
208 { 304 {
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 305 com = LinksetRoot.Position * LinksetRoot.MassRaw;
306 float totalMass = LinksetRoot.MassRaw;
307
308 foreach (BSPhysObject bp in m_taintChildren)
210 { 309 {
211 RecomputeLinksetConstraintVariables(); 310 com += bp.Position * bp.MassRaw;
212 }); 311 totalMass += bp.MassRaw;
312 }
313 if (totalMass != 0f)
314 com /= totalMass;
213 } 315 }
316
317 return com;
214 } 318 }
215 319
216 // Call each of the constraints that make up this linkset and recompute the 320 private OMV.Vector3 ComputeLinksetGeometricCenter()
217 // various transforms and variables. Used when objects are added or removed
218 // from a linkset to make sure the constraints know about the new mass and
219 // geometry.
220 // Must only be called at taint time!!
221 private bool RecomputeLinksetConstraintVariables()
222 { 321 {
223 float linksetMass = LinksetMass; 322 OMV.Vector3 com;
224 lock (m_linksetActivityLock) 323 lock (m_linksetActivityLock)
225 { 324 {
226 foreach (BSPrim child in m_children) 325 com = LinksetRoot.Position;
326
327 foreach (BSPhysObject bp in m_taintChildren)
227 { 328 {
228 BSConstraint constrain; 329 com += bp.Position * bp.MassRaw;
229 if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain))
230 {
231 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
232 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
233 constrain.RecomputeConstraintVariables(linksetMass);
234 }
235 else
236 {
237 // Non-fatal error that can happen when children are being added to the linkset but
238 // their constraints have not been created yet.
239 // Caused by the fact that m_children is built at run time but building constraints
240 // happens at taint time.
241 // m_physicsScene.Logger.ErrorFormat("[BULLETSIM LINKSET] RecomputeLinksetConstraintVariables: constraint not found for root={0}, child={1}",
242 // m_linksetRoot.Body.ID, child.Body.ID);
243 }
244 } 330 }
331 com /= (m_taintChildren.Count + 1);
245 } 332 }
246 return false; 333
334 return com;
247 } 335 }
248 336
249 // I am the root of a linkset and a new child is being added 337 // I am the root of a linkset and a new child is being added
250 // Called while LinkActivity is locked. 338 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child) 339 private void AddChildToLinkset(BSPhysObject child)
252 { 340 {
253 if (!HasChild(child)) 341 if (!HasChild(child))
254 { 342 {
255 m_children.Add(child); 343 m_children.Add(child);
256 344
257 BSPrim rootx = LinksetRoot; // capture the root as of now 345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
258 BSPrim childx = child; 346 BSPhysObject childx = child;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate() 347
348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
349
350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
260 { 351 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); 352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 353 rootx.LocalID,
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
356 // Since this is taint-time, the body and shape could have changed for the child
357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
264 }); 361 });
265 } 362 }
266 return; 363 return;
@@ -270,30 +367,34 @@ public class BSLinkset
270 // This is not being called by the child so we have to make sure the child doesn't think 367 // This is not being called by the child so we have to make sure the child doesn't think
271 // it's still connected to the linkset. 368 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 369 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent). 370 // also has to be updated (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild) 371 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
275 { 372 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild); 373 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
277 RemoveChildFromLinkset(pchild); 374 RemoveChildFromLinkset(pchild);
278 } 375 }
279 376
280 // I am the root of a linkset and one of my children is being removed. 377 // I am the root of a linkset and one of my children is being removed.
281 // Safe to call even if the child is not really in my linkset. 378 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child) 379 private void RemoveChildFromLinkset(BSPhysObject child)
283 { 380 {
284 if (m_children.Remove(child)) 381 if (m_children.Remove(child))
285 { 382 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now 383 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
287 BSPrim childx = child; 384 BSPhysObject childx = child;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 385
289 { 386 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); 387 childx.LocalID,
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 388 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
389 childx.LocalID, childx.BSBody.ptr.ToString("X"));
292 390
391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
392 {
393 m_taintChildren.Remove(child);
293 PhysicallyUnlinkAChildFromRoot(rootx, childx); 394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
395 RecomputeLinksetConstraintVariables();
294 }); 396 });
295 397
296 RecomputeLinksetConstraintVariables();
297 } 398 }
298 else 399 else
299 { 400 {
@@ -305,7 +406,7 @@ public class BSLinkset
305 406
306 // Create a constraint between me (root of linkset) and the passed prim (the child). 407 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time! 408 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) 409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
309 { 410 {
310 // Zero motion for children so they don't interpolate 411 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion(); 412 childPrim.ZeroMotion();
@@ -317,21 +418,22 @@ public class BSLinkset
317 // real world coordinate of midpoint between the two objects 418 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319 420
421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
422 rootPrim.LocalID,
423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
425 rootPrim.Position, childPrim.Position, midPoint);
426
320 // create a constraint that allows no freedom of movement between the two objects 427 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
322 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); 429
323 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
324 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint);
325 BS6DofConstraint constrain = new BS6DofConstraint( 430 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body, 431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
327 midPoint, 432
328 true, 433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
329 true 434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
330 );
331 /* NOTE: attempt to build constraint with full frame computation, etc.
332 * Using the midpoint is easier since it lets the Bullet code use the transforms
333 * of the objects. 435 * of the objects.
334 * Code left here as an example. 436 * Code left as a warning to future programmers.
335 // ================================================================================== 437 // ==================================================================================
336 // relative position normalized to the root prim 438 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); 439 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@@ -343,8 +445,7 @@ public class BSLinkset
343 445
344 // create a constraint that allows no freedom of movement between the two objects 446 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
346 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); 448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
347 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint( 449 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body, 450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
350 OMV.Vector3.Zero, 451 OMV.Vector3.Zero,
@@ -362,7 +463,7 @@ public class BSLinkset
362 // ================================================================================== 463 // ==================================================================================
363 */ 464 */
364 465
365 m_physicsScene.Constraints.AddConstraint(constrain); 466 PhysicsScene.Constraints.AddConstraint(constrain);
366 467
367 // zero linear and angular limits makes the objects unable to move in relation to each other 468 // zero linear and angular limits makes the objects unable to move in relation to each other
368 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 469 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -374,46 +475,100 @@ public class BSLinkset
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 475 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 476 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 477 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
377 478 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
378 RecomputeLinksetConstraintVariables(); 479 {
480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
481 }
379 } 482 }
380 483
381 // Remove linkage between myself and a particular child 484 // Remove linkage between myself and a particular child
485 // The root and child bodies are passed in because we need to remove the constraint between
486 // the bodies that were at unlink time.
382 // Called at taint time! 487 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) 488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
384 { 489 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 490 bool ret = false;
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID); 491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 492 rootPrim.LocalID,
493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
388 495
389 // Find the constraint for this link and get rid of it from the overall collection and from my list 496 // Find the constraint for this link and get rid of it from the overall collection and from my list
390 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body); 497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
391 503
392 // Make the child refresh its location 504 return ret;
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
394 } 505 }
395 506
396 // Remove linkage between myself and any possible children I might have 507 // Remove linkage between myself and any possible children I might have.
397 // Called at taint time! 508 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) 509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
399 { 510 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); 511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 512 bool ret = false;
402 513
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); 514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
404 } 519 }
405 520
406 // Invoke the detailed logger and output something if it's enabled. 521 // Call each of the constraints that make up this linkset and recompute the
407 private void DebugLog(string msg, params Object[] args) 522 // various transforms and variables. Used when objects are added or removed
523 // from a linkset to make sure the constraints know about the new mass and
524 // geometry.
525 // Must only be called at taint time!!
526 private void RecomputeLinksetConstraintVariables()
408 { 527 {
409 if (m_physicsScene.ShouldDebugLog) 528 float linksetMass = LinksetMass;
410 m_physicsScene.Logger.DebugFormat(msg, args); 529 foreach (BSPhysObject child in m_taintChildren)
530 {
531 BSConstraint constrain;
532 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
533 {
534 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
535 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
536 constrain.RecomputeConstraintVariables(linksetMass);
537 }
538 else
539 {
540 // Non-fatal error that happens when children are being added to the linkset but
541 // their constraints have not been created yet.
542 break;
543 }
544 }
545
546 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
547 if (m_children.Count == m_taintChildren.Count)
548 {
549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
555 foreach (BSPhysObject child in m_taintChildren)
556 {
557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
562 }
563 return;
411 } 564 }
412 565
566
413 // Invoke the detailed logger and output something if it's enabled. 567 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 568 private void DetailLog(string msg, params Object[] args)
415 { 569 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 570 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args);
417 } 572 }
418 573
419} 574}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
new file mode 100755
index 0000000..cae599c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -0,0 +1,218 @@
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 copyrightD
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37// Class to wrap all objects.
38// The rest of BulletSim doesn't need to keep checking for avatars or prims
39// unless the difference is significant.
40public abstract class BSPhysObject : PhysicsActor
41{
42 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
43 {
44 PhysicsScene = parentScene;
45 LocalID = localID;
46 PhysObjectName = name;
47 TypeName = typeName;
48
49 Linkset = new BSLinkset(PhysicsScene, this);
50
51 CollisionCollection = new CollisionEventUpdate();
52 SubscribedEventsMs = 0;
53 CollidingStep = 0;
54 CollidingGroundStep = 0;
55 }
56
57 public BSScene PhysicsScene { get; protected set; }
58 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
59 public string PhysObjectName { get; protected set; }
60 public string TypeName { get; protected set; }
61
62 public BSLinkset Linkset { get; set; }
63
64 // Return the object mass without calculating it or having side effects
65 public abstract float MassRaw { get; }
66
67 // Reference to the physical body (btCollisionObject) of this object
68 public BulletBody BSBody;
69 // Reference to the physical shape (btCollisionShape) of this object
70 public BulletShape BSShape;
71
72 // Stop all physical motion.
73 public abstract void ZeroMotion();
74
75 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
76 public virtual void StepVehicle(float timeStep) { }
77
78 // Update the physical location and motion of the object. Called with data from Bullet.
79 public abstract void UpdateProperties(EntityProperties entprop);
80
81 // Tell the object to clean up.
82 public abstract void Destroy();
83
84 public abstract OMV.Vector3 ForcePosition { get; set; }
85
86 public abstract OMV.Quaternion ForceOrientation { get; set; }
87
88 public abstract OMV.Vector3 ForceVelocity { get; set; }
89
90 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
91
92 #region Collisions
93
94 // Requested number of milliseconds between collision events. Zero means disabled.
95 protected int SubscribedEventsMs { get; set; }
96 // Given subscription, the time that a collision may be passed up
97 protected int NextCollisionOkTime { get; set; }
98 // The simulation step that last had a collision
99 protected long CollidingStep { get; set; }
100 // The simulation step that last had a collision with the ground
101 protected long CollidingGroundStep { get; set; }
102 // The collision flags we think are set in Bullet
103 protected CollisionFlags CurrentCollisionFlags { get; set; }
104
105 // The collisions that have been collected this tick
106 protected CollisionEventUpdate CollisionCollection;
107
108 // The simulation step is telling this object about a collision.
109 // Return 'true' if a collision was processed and should be sent up.
110 // Called at taint time from within the Step() function
111 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
112 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
113 {
114 bool ret = false;
115
116 // The following lines make IsColliding() and IsCollidingGround() work
117 CollidingStep = PhysicsScene.SimulationStep;
118 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
119 {
120 CollidingGroundStep = PhysicsScene.SimulationStep;
121 }
122
123 // prims in the same linkset cannot collide with each other
124 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
125 {
126 return ret;
127 }
128
129 // if someone has subscribed for collision events....
130 if (SubscribedEvents()) {
131 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
132 // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
133 // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
134
135 ret = true;
136 }
137 return ret;
138 }
139
140 // Routine to send the collected collisions into the simulator.
141 // Also handles removal of this from the collection of objects with collisions if
142 // there are no collisions from this object. Mechanism is create one last
143 // collision event to make collision_end work.
144 // Called at taint time from within the Step() function thus no locking problems
145 // with CollisionCollection and ObjectsWithNoMoreCollisions.
146 // Return 'true' if there were some actual collisions passed up
147 public virtual bool SendCollisions()
148 {
149 bool ret = true;
150
151 // throttle the collisions to the number of milliseconds specified in the subscription
152 int nowTime = PhysicsScene.SimulationNowTime;
153 if (nowTime >= NextCollisionOkTime)
154 {
155 NextCollisionOkTime = nowTime + SubscribedEventsMs;
156
157 // We are called if we previously had collisions. If there are no collisions
158 // this time, send up one last empty event so OpenSim can sense collision end.
159 if (CollisionCollection.Count == 0)
160 {
161 // If I have no collisions this time, remove me from the list of objects with collisions.
162 ret = false;
163 }
164
165 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
166 base.SendCollisionUpdate(CollisionCollection);
167
168 // The collisionCollection structure is passed around in the simulator.
169 // Make sure we don't have a handle to that one and that a new one is used for next time.
170 CollisionCollection = new CollisionEventUpdate();
171 }
172 return ret;
173 }
174
175 // Subscribe for collision events.
176 // Parameter is the millisecond rate the caller wishes collision events to occur.
177 public override void SubscribeEvents(int ms) {
178 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
179 SubscribedEventsMs = ms;
180 if (ms > 0)
181 {
182 // make sure first collision happens
183 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
184
185 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
186 {
187 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
188 });
189 }
190 else
191 {
192 // Subscribing for zero or less is the same as unsubscribing
193 UnSubscribeEvents();
194 }
195 }
196 public override void UnSubscribeEvents() {
197 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
198 SubscribedEventsMs = 0;
199 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
200 {
201 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
202 });
203 }
204 // Return 'true' if the simulator wants collision events
205 public override bool SubscribedEvents() {
206 return (SubscribedEventsMs > 0);
207 }
208
209 #endregion // Collisions
210
211 // High performance detailed logging routine used by the physical objects.
212 protected void DetailLog(string msg, params Object[] args)
213 {
214 if (PhysicsScene.PhysicsLogging.Enabled)
215 PhysicsScene.DetailLog(msg, args);
216 }
217}
218}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 0f027b8..20f5180 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. 36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the 37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine. 38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. 39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin
62 if (Util.IsWindows()) 62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the 64 // If not Windows, loading is performed by the
65 // Mono loader as specified in 65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". 66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67 67
68 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 9c20004..6a4365c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -24,6 +24,9 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
28// Uncomment this it enable code to do all shape an body memory management
29// in the C# code.
27using System; 30using System;
28using System.Reflection; 31using System.Reflection;
29using System.Collections.Generic; 32using System.Collections.Generic;
@@ -36,32 +39,20 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36 39
37namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
38{ 41{
42
39 [Serializable] 43 [Serializable]
40public sealed class BSPrim : PhysicsActor 44public sealed class BSPrim : BSPhysObject
41{ 45{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]"; 47 private static readonly string LogHeader = "[BULLETS PRIM]";
44 48
45 private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); }
46
47 private IMesh _mesh;
48 private PrimitiveBaseShape _pbs; 49 private PrimitiveBaseShape _pbs;
49 private ShapeData.PhysicsShapeType _shapeType;
50 private ulong _meshKey;
51 private ulong _hullKey;
52 private List<ConvexResult> _hulls;
53
54 private BSScene _scene;
55 public BSScene Scene { get { return _scene; } }
56 private String _avName;
57 private uint _localID = 0;
58 50
59 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. 51 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
60 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. 52 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
61 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 53 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
62 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer 54 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
63 55
64 private bool _stopped;
65 private bool _grabbed; 56 private bool _grabbed;
66 private bool _isSelected; 57 private bool _isSelected;
67 private bool _isVolumeDetect; 58 private bool _isVolumeDetect;
@@ -89,25 +80,6 @@ public sealed class BSPrim : PhysicsActor
89 private bool _kinematic; 80 private bool _kinematic;
90 private float _buoyancy; 81 private float _buoyancy;
91 82
92 // Membership in a linkset is controlled by this class.
93 private BSLinkset _linkset;
94 public BSLinkset Linkset
95 {
96 get { return _linkset; }
97 set { _linkset = value; }
98 }
99
100 private int _subscribedEventsMs = 0;
101 private int _nextCollisionOkTime = 0;
102 long _collidingStep;
103 long _collidingGroundStep;
104
105 private BulletBody m_body;
106 public BulletBody Body {
107 get { return m_body; }
108 set { m_body = value; }
109 }
110
111 private BSDynamics _vehicle; 83 private BSDynamics _vehicle;
112 84
113 private OMV.Vector3 _PIDTarget; 85 private OMV.Vector3 _PIDTarget;
@@ -122,9 +94,8 @@ public sealed class BSPrim : PhysicsActor
122 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 94 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
123 { 95 {
124 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 96 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
125 _localID = localID; 97 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
126 _avName = primName; 98 _physicsActorType = (int)ActorTypes.Prim;
127 _scene = parent_scene;
128 _position = pos; 99 _position = pos;
129 _size = size; 100 _size = size;
130 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 101 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
@@ -132,98 +103,103 @@ public sealed class BSPrim : PhysicsActor
132 _buoyancy = 1f; 103 _buoyancy = 1f;
133 _velocity = OMV.Vector3.Zero; 104 _velocity = OMV.Vector3.Zero;
134 _rotationalVelocity = OMV.Vector3.Zero; 105 _rotationalVelocity = OMV.Vector3.Zero;
135 _hullKey = 0;
136 _meshKey = 0;
137 _pbs = pbs; 106 _pbs = pbs;
138 _isPhysical = pisPhysical; 107 _isPhysical = pisPhysical;
139 _isVolumeDetect = false; 108 _isVolumeDetect = false;
140 _subscribedEventsMs = 0; 109 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 110 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 111 _restitution = PhysicsScene.Params.defaultRestitution;
143 _restitution = _scene.Params.defaultRestitution; 112 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
144 _linkset = new BSLinkset(_scene, this); // a linkset of one
145 _vehicle = new BSDynamics(this); // add vehicleness
146 _mass = CalculateMass(); 113 _mass = CalculateMass();
147 // do the actual object creation at taint time 114
115 // No body or shape yet
116 BSBody = new BulletBody(LocalID, IntPtr.Zero);
117 BSShape = new BulletShape(IntPtr.Zero);
118
148 DetailLog("{0},BSPrim.constructor,call", LocalID); 119 DetailLog("{0},BSPrim.constructor,call", LocalID);
149 _scene.TaintedObject("BSPrim.create", delegate() 120 // do the actual object creation at taint time
121 PhysicsScene.TaintedObject("BSPrim.create", delegate()
150 { 122 {
151 RecreateGeomAndObject(); 123 CreateGeomAndObject(true);
152 124
153 // Get the pointer to the physical body for this object. 125 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr);
154 // At the moment, we're still letting BulletSim manage the creation and destruction
155 // of the object. Someday we'll move that into the C# code.
156 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
157 }); 126 });
158 } 127 }
159 128
160 // called when this prim is being destroyed and we should free all the resources 129 // called when this prim is being destroyed and we should free all the resources
161 public void Destroy() 130 public override void Destroy()
162 { 131 {
163 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 132 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
164 133
165 // Undo any links between me and any other object 134 // Undo any links between me and any other object
166 BSPrim parentBefore = _linkset.LinksetRoot; 135 BSPhysObject parentBefore = Linkset.LinksetRoot;
167 int childrenBefore = _linkset.NumberOfChildren; 136 int childrenBefore = Linkset.NumberOfChildren;
168 137
169 _linkset = _linkset.RemoveMeFromLinkset(this); 138 Linkset = Linkset.RemoveMeFromLinkset(this);
170 139
171 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", 140 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
172 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 141 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
173 142
174 // Undo any vehicle properties 143 // Undo any vehicle properties
175 this.VehicleType = (int)Vehicle.TYPE_NONE; 144 this.VehicleType = (int)Vehicle.TYPE_NONE;
176 145
177 _scene.TaintedObject("BSPrim.destroy", delegate() 146 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
178 { 147 {
179 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 148 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
180 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 149 // If there are physical body and shape, release my use of same.
181 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 150 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
151 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
182 }); 152 });
183 } 153 }
184 154
185 public override bool Stopped { 155 // No one uses this property.
186 get { return _stopped; } 156 public override bool Stopped {
157 get { return false; }
187 } 158 }
188 public override OMV.Vector3 Size { 159 public override OMV.Vector3 Size {
189 get { return _size; } 160 get { return _size; }
190 set { 161 set {
191 _size = value; 162 _size = value;
192 _scene.TaintedObject("BSPrim.setSize", delegate() 163 PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
193 { 164 {
194 _mass = CalculateMass(); // changing size changes the mass 165 _mass = CalculateMass(); // changing size changes the mass
195 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); 166 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
196 // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); 167 // scale and margins are set.
197 RecreateGeomAndObject(); 168 CreateGeomAndObject(true);
169 // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
198 }); 170 });
199 } 171 }
172 }
173 // Scale is what we set in the physics engine. It is different than 'size' in that
174 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
175 public OMV.Vector3 Scale
176 {
177 get { return _scale; }
178 set { _scale = value; }
200 } 179 }
201 public override PrimitiveBaseShape Shape { 180 public override PrimitiveBaseShape Shape {
202 set { 181 set {
203 _pbs = value; 182 _pbs = value;
204 _scene.TaintedObject("BSPrim.setShape", delegate() 183 PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
205 { 184 {
206 _mass = CalculateMass(); // changing the shape changes the mass 185 _mass = CalculateMass(); // changing the shape changes the mass
207 RecreateGeomAndObject(); 186 CreateGeomAndObject(true);
208 }); 187 });
209 } 188 }
210 }
211 public override uint LocalID {
212 set { _localID = value; }
213 get { return _localID; }
214 } 189 }
215 public override bool Grabbed { 190 public override bool Grabbed {
216 set { _grabbed = value; 191 set { _grabbed = value;
217 } 192 }
218 } 193 }
219 public override bool Selected { 194 public override bool Selected {
220 set { 195 set {
221 _isSelected = value; 196 _isSelected = value;
222 _scene.TaintedObject("BSPrim.setSelected", delegate() 197 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
223 { 198 {
224 SetObjectDynamic(); 199 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
200 SetObjectDynamic(false);
225 }); 201 });
226 } 202 }
227 } 203 }
228 public override void CrossingFailure() { return; } 204 public override void CrossingFailure() { return; }
229 205
@@ -232,158 +208,227 @@ public sealed class BSPrim : PhysicsActor
232 BSPrim parent = obj as BSPrim; 208 BSPrim parent = obj as BSPrim;
233 if (parent != null) 209 if (parent != null)
234 { 210 {
235 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); 211 BSPhysObject parentBefore = Linkset.LinksetRoot;
236 BSPrim parentBefore = _linkset.LinksetRoot; 212 int childrenBefore = Linkset.NumberOfChildren;
237 int childrenBefore = _linkset.NumberOfChildren;
238 213
239 _linkset = parent.Linkset.AddMeToLinkset(this); 214 Linkset = parent.Linkset.AddMeToLinkset(this);
240 215
241 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 216 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
242 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 217 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
243 } 218 }
244 return; 219 return;
245 } 220 }
246 221
247 // delink me from my linkset 222 // delink me from my linkset
248 public override void delink() { 223 public override void delink() {
249 // TODO: decide if this parent checking needs to happen at taint time 224 // TODO: decide if this parent checking needs to happen at taint time
250 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 225 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
251 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
252 _linkset.LinksetRoot._avName+"/"+_linkset.LinksetRoot.LocalID.ToString());
253 226
254 BSPrim parentBefore = _linkset.LinksetRoot; 227 BSPhysObject parentBefore = Linkset.LinksetRoot;
255 int childrenBefore = _linkset.NumberOfChildren; 228 int childrenBefore = Linkset.NumberOfChildren;
256 229
257 _linkset = _linkset.RemoveMeFromLinkset(this); 230 Linkset = Linkset.RemoveMeFromLinkset(this);
258 231
259 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 232 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
260 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 233 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
261 return; 234 return;
262 } 235 }
263 236
264 // Set motion values to zero. 237 // Set motion values to zero.
265 // Do it to the properties so the values get set in the physics engine. 238 // Do it to the properties so the values get set in the physics engine.
266 // Push the setting of the values to the viewer. 239 // Push the setting of the values to the viewer.
267 // Called at taint time! 240 // Called at taint time!
268 public void ZeroMotion() 241 public override void ZeroMotion()
269 { 242 {
270 _velocity = OMV.Vector3.Zero; 243 _velocity = OMV.Vector3.Zero;
271 _acceleration = OMV.Vector3.Zero; 244 _acceleration = OMV.Vector3.Zero;
272 _rotationalVelocity = OMV.Vector3.Zero; 245 _rotationalVelocity = OMV.Vector3.Zero;
273 246
274 // Zero some other properties directly into the physics engine 247 // Zero some other properties directly into the physics engine
275 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); 248 BulletSimAPI.ClearForces2(BSBody.ptr);
276 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
277 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
278 BulletSimAPI.ClearForces2(Body.Ptr);
279 } 249 }
280 250
281 public override void LockAngularMotion(OMV.Vector3 axis) 251 public override void LockAngularMotion(OMV.Vector3 axis)
282 { 252 {
283 // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 253 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
284 return; 254 return;
285 } 255 }
286 256
287 public override OMV.Vector3 Position { 257 public override OMV.Vector3 Position {
288 get { 258 get {
289 if (!_linkset.IsRoot(this)) 259 if (!Linkset.IsRoot(this))
290 // child prims move around based on their parent. Need to get the latest location 260 // child prims move around based on their parent. Need to get the latest location
291 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 261 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
292 262
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times 263 // don't do the GetObjectPosition for root elements because this function is called a zillion times
294 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 264 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position; 265 return _position;
296 } 266 }
297 set { 267 set {
268 // If you must push the position into the physics engine, use ForcePosition.
269 if (_position == value)
270 {
271 return;
272 }
298 _position = value; 273 _position = value;
299 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 274 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
300 _scene.TaintedObject("BSPrim.setPosition", delegate() 275 PositionSanityCheck();
276 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
301 { 277 {
302 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 278 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
303 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 279 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
304 }); 280 });
305 } 281 }
282 }
283 public override OMV.Vector3 ForcePosition {
284 get {
285 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
286 return _position;
287 }
288 set {
289 _position = value;
290 PositionSanityCheck();
291 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
292 }
293 }
294
295 // Check that the current position is sane and, if not, modify the position to make it so.
296 // Check for being below terrain and being out of bounds.
297 // Returns 'true' of the position was made sane by some action.
298 private bool PositionSanityCheck()
299 {
300 bool ret = false;
301
302 // If totally below the ground, move the prim up
303 // TODO: figure out the right solution for this... only for dynamic objects?
304 /*
305 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
306 if (Position.Z < terrainHeight)
307 {
308 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
309 _position.Z = terrainHeight + 2.0f;
310 ret = true;
311 }
312 */
313 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
314 {
315 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
316 if (Position.Z < waterHeight)
317 {
318 _position.Z = waterHeight;
319 ret = true;
320 }
321 }
322
323 // TODO: check for out of bounds
324 return ret;
325 }
326
327 // A version of the sanity check that also makes sure a new position value is
328 // pushed back to the physics engine. This routine would be used by anyone
329 // who is not already pushing the value.
330 private bool PositionSanityCheck2(bool inTaintTime)
331 {
332 bool ret = false;
333 if (PositionSanityCheck())
334 {
335 // The new position value must be pushed into the physics engine but we can't
336 // just assign to "Position" because of potential call loops.
337 BSScene.TaintCallback sanityOperation = delegate()
338 {
339 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
340 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
341 };
342 if (inTaintTime)
343 sanityOperation();
344 else
345 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
346
347 ret = true;
348 }
349 return ret;
306 } 350 }
307 351
308 // Return the effective mass of the object. 352 // Return the effective mass of the object.
309 // If there are multiple items in the linkset, add them together for the root 353 // If there are multiple items in the linkset, add them together for the root
310 public override float Mass 354 public override float Mass
311 { 355 {
312 get 356 get
313 { 357 {
314 return _linkset.LinksetMass; 358 // return Linkset.LinksetMass;
359 return _mass;
315 } 360 }
316 } 361 }
317 362
318 // used when we only want this prim's mass and not the linkset thing 363 // used when we only want this prim's mass and not the linkset thing
319 public float MassRaw { get { return _mass; } } 364 public override float MassRaw { get { return _mass; } }
320 365
321 // Is this used? 366 // Is this used?
322 public override OMV.Vector3 CenterOfMass 367 public override OMV.Vector3 CenterOfMass
323 { 368 {
324 get { return _linkset.CenterOfMass; } 369 get { return Linkset.CenterOfMass; }
325 } 370 }
326 371
327 // Is this used? 372 // Is this used?
328 public override OMV.Vector3 GeometricCenter 373 public override OMV.Vector3 GeometricCenter
329 { 374 {
330 get { return _linkset.GeometricCenter; } 375 get { return Linkset.GeometricCenter; }
331 } 376 }
332 377
333 public override OMV.Vector3 Force { 378 public override OMV.Vector3 Force {
334 get { return _force; } 379 get { return _force; }
335 set { 380 set {
336 _force = value; 381 _force = value;
337 _scene.TaintedObject("BSPrim.setForce", delegate() 382 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
338 { 383 {
339 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 384 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
340 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 385 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
341 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
342 }); 386 });
343 } 387 }
344 } 388 }
345 389
346 public override int VehicleType { 390 public override int VehicleType {
347 get { 391 get {
348 return (int)_vehicle.Type; // if we are a vehicle, return that type 392 return (int)_vehicle.Type; // if we are a vehicle, return that type
349 } 393 }
350 set { 394 set {
351 Vehicle type = (Vehicle)value; 395 Vehicle type = (Vehicle)value;
352 BSPrim vehiclePrim = this; 396
353 _scene.TaintedObject("setVehicleType", delegate() 397 // Tell the scene about the vehicle so it will get processing each frame.
398 PhysicsScene.VehicleInSceneTypeChanged(this, type);
399
400 PhysicsScene.TaintedObject("setVehicleType", delegate()
354 { 401 {
355 // Done at taint time so we're sure the physics engine is not using the variables 402 // Done at taint time so we're sure the physics engine is not using the variables
356 // Vehicle code changes the parameters for this vehicle type. 403 // Vehicle code changes the parameters for this vehicle type.
357 _vehicle.ProcessTypeChange(type); 404 this._vehicle.ProcessTypeChange(type);
358 // Tell the scene about the vehicle so it will get processing each frame.
359 _scene.VehicleInSceneTypeChanged(this, type);
360 }); 405 });
361 } 406 }
362 } 407 }
363 public override void VehicleFloatParam(int param, float value) 408 public override void VehicleFloatParam(int param, float value)
364 { 409 {
365 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 410 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
366 { 411 {
367 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 412 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
368 }); 413 });
369 } 414 }
370 public override void VehicleVectorParam(int param, OMV.Vector3 value) 415 public override void VehicleVectorParam(int param, OMV.Vector3 value)
371 { 416 {
372 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 417 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
373 { 418 {
374 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 419 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
375 }); 420 });
376 } 421 }
377 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 422 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
378 { 423 {
379 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 424 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
380 { 425 {
381 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 426 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
382 }); 427 });
383 } 428 }
384 public override void VehicleFlags(int param, bool remove) 429 public override void VehicleFlags(int param, bool remove)
385 { 430 {
386 _scene.TaintedObject("BSPrim.VehicleFlags", delegate() 431 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
387 { 432 {
388 _vehicle.ProcessVehicleFlags(param, remove); 433 _vehicle.ProcessVehicleFlags(param, remove);
389 }); 434 });
@@ -391,83 +436,114 @@ public sealed class BSPrim : PhysicsActor
391 436
392 // Called each simulation step to advance vehicle characteristics. 437 // Called each simulation step to advance vehicle characteristics.
393 // Called from Scene when doing simulation step so we're in taint processing time. 438 // Called from Scene when doing simulation step so we're in taint processing time.
394 public void StepVehicle(float timeStep) 439 public override void StepVehicle(float timeStep)
395 { 440 {
396 if (IsPhysical) 441 if (IsPhysical)
442 {
397 _vehicle.Step(timeStep); 443 _vehicle.Step(timeStep);
444 }
398 } 445 }
399 446
400 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 447 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
401 public override void SetVolumeDetect(int param) { 448 public override void SetVolumeDetect(int param) {
402 bool newValue = (param != 0); 449 bool newValue = (param != 0);
403 _isVolumeDetect = newValue; 450 if (_isVolumeDetect != newValue)
404 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
405 { 451 {
406 SetObjectDynamic(); 452 _isVolumeDetect = newValue;
407 }); 453 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
408 return; 454 {
455 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
456 SetObjectDynamic(true);
457 });
458 }
459 return;
409 } 460 }
410 461 public override OMV.Vector3 Velocity {
411 public override OMV.Vector3 Velocity { 462 get { return _velocity; }
412 get { return _velocity; }
413 set { 463 set {
414 _velocity = value; 464 _velocity = value;
415 _scene.TaintedObject("BSPrim.setVelocity", delegate() 465 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
416 { 466 {
417 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 467 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
418 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 468 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
419 }); 469 });
420 } 470 }
421 } 471 }
422 public override OMV.Vector3 Torque { 472 public override OMV.Vector3 ForceVelocity {
423 get { return _torque; } 473 get { return _velocity; }
424 set { _torque = value; 474 set {
475 _velocity = value;
476 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
477 }
478 }
479 public override OMV.Vector3 Torque {
480 get { return _torque; }
481 set { _torque = value;
425 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 482 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
426 } 483 }
427 } 484 }
428 public override float CollisionScore { 485 public override float CollisionScore {
429 get { return _collisionScore; } 486 get { return _collisionScore; }
430 set { _collisionScore = value; 487 set { _collisionScore = value;
431 } 488 }
432 } 489 }
433 public override OMV.Vector3 Acceleration { 490 public override OMV.Vector3 Acceleration {
434 get { return _acceleration; } 491 get { return _acceleration; }
435 set { _acceleration = value; } 492 set { _acceleration = value; }
436 } 493 }
437 public override OMV.Quaternion Orientation { 494 public override OMV.Quaternion Orientation {
438 get { 495 get {
439 if (!_linkset.IsRoot(this)) 496 if (!Linkset.IsRoot(this))
440 { 497 {
441 // Children move around because tied to parent. Get a fresh value. 498 // Children move around because tied to parent. Get a fresh value.
442 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); 499 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
443 } 500 }
444 return _orientation; 501 return _orientation;
445 } 502 }
446 set { 503 set {
504 if (_orientation == value)
505 return;
447 _orientation = value; 506 _orientation = value;
448 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 507 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
449 _scene.TaintedObject("BSPrim.setOrientation", delegate() 508 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
450 { 509 {
451 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 510 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
452 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 511 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
453 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 512 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
454 }); 513 });
455 } 514 }
515 }
516 // Go directly to Bullet to get/set the value.
517 public override OMV.Quaternion ForceOrientation
518 {
519 get
520 {
521 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
522 return _orientation;
523 }
524 set
525 {
526 _orientation = value;
527 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
528 }
456 } 529 }
457 public override int PhysicsActorType { 530 public override int PhysicsActorType {
458 get { return _physicsActorType; } 531 get { return _physicsActorType; }
459 set { _physicsActorType = value; 532 set { _physicsActorType = value; }
460 }
461 } 533 }
462 public override bool IsPhysical { 534 public override bool IsPhysical {
463 get { return _isPhysical; } 535 get { return _isPhysical; }
464 set { 536 set {
465 _isPhysical = value; 537 if (_isPhysical != value)
466 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
467 { 538 {
468 SetObjectDynamic(); 539 _isPhysical = value;
469 }); 540 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
470 } 541 {
542 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
543 SetObjectDynamic(true);
544 });
545 }
546 }
471 } 547 }
472 548
473 // An object is static (does not move) if selected or not physical 549 // An object is static (does not move) if selected or not physical
@@ -477,57 +553,201 @@ public sealed class BSPrim : PhysicsActor
477 } 553 }
478 554
479 // An object is solid if it's not phantom and if it's not doing VolumeDetect 555 // An object is solid if it's not phantom and if it's not doing VolumeDetect
480 private bool IsSolid 556 public bool IsSolid
481 { 557 {
482 get { return !IsPhantom && !_isVolumeDetect; } 558 get { return !IsPhantom && !_isVolumeDetect; }
483 } 559 }
484 560
485 // Make gravity work if the object is physical and not selected 561 // Make gravity work if the object is physical and not selected
486 // No locking here because only called when it is safe 562 // Called at taint-time!!
487 private void SetObjectDynamic() 563 private void SetObjectDynamic(bool forceRebuild)
564 {
565 // Recreate the physical object if necessary
566 CreateGeomAndObject(forceRebuild);
567 }
568
569 // Convert the simulator's physical properties into settings on BulletSim objects.
570 // There are four flags we're interested in:
571 // IsStatic: Object does not move, otherwise the object has mass and moves
572 // isSolid: other objects bounce off of this object
573 // isVolumeDetect: other objects pass through but can generate collisions
574 // collisionEvents: whether this object returns collision events
575 private void UpdatePhysicalParameters()
576 {
577 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
578
579 // Mangling all the physical properties requires the object not be in the physical world.
580 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
581 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
582
583 // Set up the object physicalness (does gravity and collisions move this object)
584 MakeDynamic(IsStatic);
585
586 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
587 _vehicle.Refresh();
588
589 // Arrange for collision events if the simulator wants them
590 EnableCollisions(SubscribedEvents());
591
592 // Make solid or not (do things bounce off or pass through this object).
593 MakeSolid(IsSolid);
594
595 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
596
597 // Rebuild its shape
598 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
599
600 // Collision filter can be set only when the object is in the world
601 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
602 {
603 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
604 }
605
606 // Recompute any linkset parameters.
607 // When going from non-physical to physical, this re-enables the constraints that
608 // had been automatically disabled when the mass was set to zero.
609 Linkset.Refresh(this, true);
610
611 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
612 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
613 }
614
615 // "Making dynamic" means changing to and from static.
616 // When static, gravity does not effect the object and it is fixed in space.
617 // When dynamic, the object can fall and be pushed by others.
618 // This is independent of its 'solidness' which controls what passes through
619 // this object and what interacts with it.
620 private void MakeDynamic(bool makeStatic)
488 { 621 {
489 // RA: remove this for the moment. 622 if (makeStatic)
490 // The problem is that dynamic objects are hulls so if we are becoming physical 623 {
491 // the shape has to be checked and possibly built. 624 // Become a Bullet 'static' object type
492 // Maybe a VerifyCorrectPhysicalShape() routine? 625 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
493 // RecreateGeomAndObject(); 626 // Stop all movement
627 BulletSimAPI.ClearAllForces2(BSBody.ptr);
628 // Center of mass is at the center of the object
629 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
630 // Mass is zero which disables a bunch of physics stuff in Bullet
631 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
632 // There is no inertia in a static object
633 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
634 // There can be special things needed for implementing linksets
635 Linkset.MakeStatic(this);
636 // The activation state is 'disabled' so Bullet will not try to act on it.
637 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
638 // Start it out sleeping and physical actions could wake it up.
639 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
640
641 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
642 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
643 }
644 else
645 {
646 // Not a Bullet static object
647 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
648
649 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
650 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
651 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
652
653 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
654 BulletSimAPI.ClearAllForces2(BSBody.ptr);
655
656 // For good measure, make sure the transform is set through to the motion state
657 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
658
659 // A dynamic object has mass
660 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
661 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
662 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
663 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
494 664
495 // Bullet wants static objects to have a mass of zero 665 // Various values for simulation limits
496 float mass = IsStatic ? 0f : _mass; 666 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
667 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
668 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
669 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
497 670
498 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); 671 // There might be special things needed for implementing linksets.
672 Linkset.MakeDynamic(this);
673
674 // Force activation of the object so Bullet will act on it.
675 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
676 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
677 // BulletSimAPI.Activate2(BSBody.ptr, true);
678
679 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
680 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
681 }
682 }
499 683
500 // recompute any linkset parameters 684 // "Making solid" means that other object will not pass through this object.
501 _linkset.Refresh(this); 685 // To make transparent, we create a Bullet ghost object.
686 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
687 // the functions after this one set up the state of a possibly newly created collision body.
688 private void MakeSolid(bool makeSolid)
689 {
690 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
691 if (makeSolid)
692 {
693 // Verify the previous code created the correct shape for this type of thing.
694 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
695 {
696 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
697 }
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
699 }
700 else
701 {
702 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
703 {
704 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
705 }
706 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
707 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
708 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
709 }
710 }
502 711
503 CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); 712 // Turn on or off the flag controlling whether collision events are returned to the simulator.
504 // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); 713 private void EnableCollisions(bool wantsCollisionEvents)
714 {
715 if (wantsCollisionEvents)
716 {
717 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
718 }
719 else
720 {
721 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
722 }
505 } 723 }
506 724
507 // prims don't fly 725 // prims don't fly
508 public override bool Flying { 726 public override bool Flying {
509 get { return _flying; } 727 get { return _flying; }
510 set { _flying = value; } 728 set {
729 _flying = value;
730 }
511 } 731 }
512 public override bool SetAlwaysRun { 732 public override bool SetAlwaysRun {
513 get { return _setAlwaysRun; } 733 get { return _setAlwaysRun; }
514 set { _setAlwaysRun = value; } 734 set { _setAlwaysRun = value; }
515 } 735 }
516 public override bool ThrottleUpdates { 736 public override bool ThrottleUpdates {
517 get { return _throttleUpdates; } 737 get { return _throttleUpdates; }
518 set { _throttleUpdates = value; } 738 set { _throttleUpdates = value; }
519 } 739 }
520 public override bool IsColliding { 740 public override bool IsColliding {
521 get { return (_collidingStep == _scene.SimulationStep); } 741 get { return (CollidingStep == PhysicsScene.SimulationStep); }
522 set { _isColliding = value; } 742 set { _isColliding = value; }
523 } 743 }
524 public override bool CollidingGround { 744 public override bool CollidingGround {
525 get { return (_collidingGroundStep == _scene.SimulationStep); } 745 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
526 set { _collidingGround = value; } 746 set { _collidingGround = value; }
527 } 747 }
528 public override bool CollidingObj { 748 public override bool CollidingObj {
529 get { return _collidingObj; } 749 get { return _collidingObj; }
530 set { _collidingObj = value; } 750 set { _collidingObj = value; }
531 } 751 }
532 public bool IsPhantom { 752 public bool IsPhantom {
533 get { 753 get {
@@ -537,10 +757,19 @@ public sealed class BSPrim : PhysicsActor
537 return false; 757 return false;
538 } 758 }
539 } 759 }
540 public override bool FloatOnWater { 760 public override bool FloatOnWater {
541 set { _floatOnWater = value; } 761 set {
762 _floatOnWater = value;
763 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
764 {
765 if (_floatOnWater)
766 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
767 else
768 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
769 });
770 }
542 } 771 }
543 public override OMV.Vector3 RotationalVelocity { 772 public override OMV.Vector3 RotationalVelocity {
544 get { 773 get {
545 /* 774 /*
546 OMV.Vector3 pv = OMV.Vector3.Zero; 775 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -552,58 +781,69 @@ public sealed class BSPrim : PhysicsActor
552 */ 781 */
553 782
554 return _rotationalVelocity; 783 return _rotationalVelocity;
555 } 784 }
556 set { 785 set {
557 _rotationalVelocity = value; 786 _rotationalVelocity = value;
558 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 787 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
559 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 788 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
560 { 789 {
561 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 790 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
562 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 791 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
563 }); 792 });
564 } 793 }
794 }
795 public override OMV.Vector3 ForceRotationalVelocity {
796 get {
797 return _rotationalVelocity;
798 }
799 set {
800 _rotationalVelocity = value;
801 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
802 }
565 } 803 }
566 public override bool Kinematic { 804 public override bool Kinematic {
567 get { return _kinematic; } 805 get { return _kinematic; }
568 set { _kinematic = value; 806 set { _kinematic = value;
569 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 807 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
570 } 808 }
571 } 809 }
572 public override float Buoyancy { 810 public override float Buoyancy {
573 get { return _buoyancy; } 811 get { return _buoyancy; }
574 set { 812 set {
575 _buoyancy = value; 813 _buoyancy = value;
576 _scene.TaintedObject("BSPrim.setBuoyancy", delegate() 814 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
577 { 815 {
578 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 816 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
579 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 817 // Buoyancy is faked by changing the gravity applied to the object
818 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
819 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
580 }); 820 });
581 } 821 }
582 } 822 }
583 823
584 // Used for MoveTo 824 // Used for MoveTo
585 public override OMV.Vector3 PIDTarget { 825 public override OMV.Vector3 PIDTarget {
586 set { _PIDTarget = value; } 826 set { _PIDTarget = value; }
587 } 827 }
588 public override bool PIDActive { 828 public override bool PIDActive {
589 set { _usePID = value; } 829 set { _usePID = value; }
590 } 830 }
591 public override float PIDTau { 831 public override float PIDTau {
592 set { _PIDTau = value; } 832 set { _PIDTau = value; }
593 } 833 }
594 834
595 // Used for llSetHoverHeight and maybe vehicle height 835 // Used for llSetHoverHeight and maybe vehicle height
596 // Hover Height will override MoveTo target's Z 836 // Hover Height will override MoveTo target's Z
597 public override bool PIDHoverActive { 837 public override bool PIDHoverActive {
598 set { _useHoverPID = value; } 838 set { _useHoverPID = value; }
599 } 839 }
600 public override float PIDHoverHeight { 840 public override float PIDHoverHeight {
601 set { _PIDHoverHeight = value; } 841 set { _PIDHoverHeight = value; }
602 } 842 }
603 public override PIDHoverType PIDHoverType { 843 public override PIDHoverType PIDHoverType {
604 set { _PIDHoverType = value; } 844 set { _PIDHoverType = value; }
605 } 845 }
606 public override float PIDHoverTau { 846 public override float PIDHoverTau {
607 set { _PIDHoverTao = value; } 847 set { _PIDHoverTao = value; }
608 } 848 }
609 849
@@ -615,6 +855,9 @@ public sealed class BSPrim : PhysicsActor
615 855
616 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 856 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
617 public override void AddForce(OMV.Vector3 force, bool pushforce) { 857 public override void AddForce(OMV.Vector3 force, bool pushforce) {
858 AddForce(force, pushforce, false);
859 }
860 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
618 // for an object, doesn't matter if force is a pushforce or not 861 // for an object, doesn't matter if force is a pushforce or not
619 if (force.IsFinite()) 862 if (force.IsFinite())
620 { 863 {
@@ -624,56 +867,38 @@ public sealed class BSPrim : PhysicsActor
624 } 867 }
625 else 868 else
626 { 869 {
627 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 870 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
628 return; 871 return;
629 } 872 }
630 _scene.TaintedObject("BSPrim.AddForce", delegate() 873 BSScene.TaintCallback addForceOperation = delegate()
631 { 874 {
632 OMV.Vector3 fSum = OMV.Vector3.Zero; 875 OMV.Vector3 fSum = OMV.Vector3.Zero;
633 lock (m_accumulatedForces) 876 lock (m_accumulatedForces)
634 { 877 {
878 // Sum the accumulated additional forces for one big force to apply once.
635 foreach (OMV.Vector3 v in m_accumulatedForces) 879 foreach (OMV.Vector3 v in m_accumulatedForces)
636 { 880 {
637 fSum += v; 881 fSum += v;
638 } 882 }
639 m_accumulatedForces.Clear(); 883 m_accumulatedForces.Clear();
640 } 884 }
641 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); 885 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
642 BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); 886 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
643 }); 887 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
888 };
889 if (inTaintTime)
890 addForceOperation();
891 else
892 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
644 } 893 }
645 894
646 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 895 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
647 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 896 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
648 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 897 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
649 } 898 }
650 public override void SetMomentum(OMV.Vector3 momentum) { 899 public override void SetMomentum(OMV.Vector3 momentum) {
651 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 900 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
652 } 901 }
653 public override void SubscribeEvents(int ms) {
654 _subscribedEventsMs = ms;
655 if (ms > 0)
656 {
657 // make sure first collision happens
658 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
659
660 Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
661 {
662 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
663 });
664 }
665 }
666 public override void UnSubscribeEvents() {
667 _subscribedEventsMs = 0;
668 Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
669 {
670 BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
671 });
672 }
673 public override bool SubscribedEvents() {
674 return (_subscribedEventsMs > 0);
675 }
676
677 #region Mass Calculation 902 #region Mass Calculation
678 903
679 private float CalculateMass() 904 private float CalculateMass()
@@ -683,8 +908,8 @@ public sealed class BSPrim : PhysicsActor
683 908
684 float returnMass = 0; 909 float returnMass = 0;
685 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 910 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
686 float hollowVolume = hollowAmount * hollowAmount; 911 float hollowVolume = hollowAmount * hollowAmount;
687 912
688 switch (_pbs.ProfileShape) 913 switch (_pbs.ProfileShape)
689 { 914 {
690 case ProfileShape.Square: 915 case ProfileShape.Square:
@@ -720,16 +945,16 @@ public sealed class BSPrim : PhysicsActor
720 945
721 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 946 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
722 { 947 {
723 //a tube 948 //a tube
724 949
725 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 950 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
726 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 951 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
727 volume -= volume*tmp*tmp; 952 volume -= volume*tmp*tmp;
728 953
729 if (hollowAmount > 0.0) 954 if (hollowAmount > 0.0)
730 { 955 {
731 hollowVolume *= hollowAmount; 956 hollowVolume *= hollowAmount;
732 957
733 switch (_pbs.HollowShape) 958 switch (_pbs.HollowShape)
734 { 959 {
735 case HollowShape.Square: 960 case HollowShape.Square:
@@ -788,7 +1013,7 @@ public sealed class BSPrim : PhysicsActor
788 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 1013 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
789 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1014 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
790 volume *= (1.0f - tmp * tmp); 1015 volume *= (1.0f - tmp * tmp);
791 1016
792 if (hollowAmount > 0.0) 1017 if (hollowAmount > 0.0)
793 { 1018 {
794 1019
@@ -967,296 +1192,65 @@ public sealed class BSPrim : PhysicsActor
967 if (returnMass <= 0) 1192 if (returnMass <= 0)
968 returnMass = 0.0001f; 1193 returnMass = 0.0001f;
969 1194
970 if (returnMass > _scene.MaximumObjectMass) 1195 if (returnMass > PhysicsScene.MaximumObjectMass)
971 returnMass = _scene.MaximumObjectMass; 1196 returnMass = PhysicsScene.MaximumObjectMass;
972 1197
973 return returnMass; 1198 return returnMass;
974 }// end CalculateMass 1199 }// end CalculateMass
975 #endregion Mass Calculation 1200 #endregion Mass Calculation
976 1201
977 // Create the geometry information in Bullet for later use
978 // The objects needs a hull if it's physical otherwise a mesh is enough
979 // No locking here because this is done when we know physics is not simulating
980 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
981 // Returns 'true' if the geometry was rebuilt
982 private bool CreateGeom(bool forceRebuild)
983 {
984 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
985 bool ret = false;
986 if (!_scene.NeedsMeshing(_pbs))
987 {
988 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
989 {
990 // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
991 // {
992 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
993 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
994 {
995 // DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
996 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
997 // Bullet native objects are scaled by the Bullet engine so pass the size in
998 _scale = _size;
999 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1000 ret = true;
1001 }
1002 // }
1003 }
1004 else
1005 {
1006 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
1007 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
1008 {
1009 // DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
1010 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
1011 _scale = _size;
1012 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1013 ret = true;
1014 }
1015 }
1016 }
1017 else
1018 {
1019 if (IsPhysical)
1020 {
1021 if (forceRebuild || _hullKey == 0)
1022 {
1023 // physical objects require a hull for interaction.
1024 // This will create the mesh if it doesn't already exist
1025 CreateGeomHull();
1026 ret = true;
1027 }
1028 }
1029 else
1030 {
1031 if (forceRebuild || _meshKey == 0)
1032 {
1033 // Static (non-physical) objects only need a mesh for bumping into
1034 CreateGeomMesh();
1035 ret = true;
1036 }
1037 }
1038 }
1039 return ret;
1040 }
1041
1042 // No locking here because this is done when we know physics is not simulating
1043 private void CreateGeomMesh()
1044 {
1045 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1046 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
1047 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
1048
1049 // if this new shape is the same as last time, don't recreate the mesh
1050 if (_meshKey == newMeshKey) return;
1051
1052 // DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey);
1053 // Since we're recreating new, get rid of any previously generated shape
1054 if (_meshKey != 0)
1055 {
1056 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1057 // DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
1058 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1059 _mesh = null;
1060 _meshKey = 0;
1061 }
1062
1063 _meshKey = newMeshKey;
1064 // always pass false for physicalness as this creates some sort of bounding box which we don't need
1065 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
1066
1067 int[] indices = _mesh.getIndexListAsInt();
1068 List<OMV.Vector3> vertices = _mesh.getVertexList();
1069
1070 float[] verticesAsFloats = new float[vertices.Count * 3];
1071 int vi = 0;
1072 foreach (OMV.Vector3 vv in vertices)
1073 {
1074 verticesAsFloats[vi++] = vv.X;
1075 verticesAsFloats[vi++] = vv.Y;
1076 verticesAsFloats[vi++] = vv.Z;
1077 }
1078
1079 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
1080 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
1081 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
1082 vertices.Count, verticesAsFloats);
1083
1084 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1085 // meshes are already scaled by the meshmerizer
1086 _scale = new OMV.Vector3(1f, 1f, 1f);
1087 // DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID);
1088 return;
1089 }
1090
1091 // No locking here because this is done when we know physics is not simulating
1092 private void CreateGeomHull()
1093 {
1094 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1095 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
1096 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
1097
1098 // if the hull hasn't changed, don't rebuild it
1099 if (newHullKey == _hullKey) return;
1100
1101 // DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey);
1102
1103 // Since we're recreating new, get rid of any previously generated shape
1104 if (_hullKey != 0)
1105 {
1106 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1107 // DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey);
1108 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1109 _hullKey = 0;
1110 }
1111
1112 _hullKey = newHullKey;
1113
1114 // Make sure the underlying mesh exists and is correct
1115 CreateGeomMesh();
1116
1117 int[] indices = _mesh.getIndexListAsInt();
1118 List<OMV.Vector3> vertices = _mesh.getVertexList();
1119
1120 //format conversion from IMesh format to DecompDesc format
1121 List<int> convIndices = new List<int>();
1122 List<float3> convVertices = new List<float3>();
1123 for (int ii = 0; ii < indices.GetLength(0); ii++)
1124 {
1125 convIndices.Add(indices[ii]);
1126 }
1127 foreach (OMV.Vector3 vv in vertices)
1128 {
1129 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
1130 }
1131
1132 // setup and do convex hull conversion
1133 _hulls = new List<ConvexResult>();
1134 DecompDesc dcomp = new DecompDesc();
1135 dcomp.mIndices = convIndices;
1136 dcomp.mVertices = convVertices;
1137 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1138 // create the hull into the _hulls variable
1139 convexBuilder.process(dcomp);
1140
1141 // Convert the vertices and indices for passing to unmanaged.
1142 // The hull information is passed as a large floating point array.
1143 // The format is:
1144 // convHulls[0] = number of hulls
1145 // convHulls[1] = number of vertices in first hull
1146 // convHulls[2] = hull centroid X coordinate
1147 // convHulls[3] = hull centroid Y coordinate
1148 // convHulls[4] = hull centroid Z coordinate
1149 // convHulls[5] = first hull vertex X
1150 // convHulls[6] = first hull vertex Y
1151 // convHulls[7] = first hull vertex Z
1152 // convHulls[8] = second hull vertex X
1153 // ...
1154 // convHulls[n] = number of vertices in second hull
1155 // convHulls[n+1] = second hull centroid X coordinate
1156 // ...
1157 //
1158 // TODO: is is very inefficient. Someday change the convex hull generator to return
1159 // data structures that do not need to be converted in order to pass to Bullet.
1160 // And maybe put the values directly into pinned memory rather than marshaling.
1161 int hullCount = _hulls.Count;
1162 int totalVertices = 1; // include one for the count of the hulls
1163 foreach (ConvexResult cr in _hulls)
1164 {
1165 totalVertices += 4; // add four for the vertex count and centroid
1166 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
1167 }
1168 float[] convHulls = new float[totalVertices];
1169
1170 convHulls[0] = (float)hullCount;
1171 int jj = 1;
1172 foreach (ConvexResult cr in _hulls)
1173 {
1174 // copy vertices for index access
1175 float3[] verts = new float3[cr.HullVertices.Count];
1176 int kk = 0;
1177 foreach (float3 ff in cr.HullVertices)
1178 {
1179 verts[kk++] = ff;
1180 }
1181
1182 // add to the array one hull's worth of data
1183 convHulls[jj++] = cr.HullIndices.Count;
1184 convHulls[jj++] = 0f; // centroid x,y,z
1185 convHulls[jj++] = 0f;
1186 convHulls[jj++] = 0f;
1187 foreach (int ind in cr.HullIndices)
1188 {
1189 convHulls[jj++] = verts[ind].x;
1190 convHulls[jj++] = verts[ind].y;
1191 convHulls[jj++] = verts[ind].z;
1192 }
1193 }
1194
1195 // create the hull definition in Bullet
1196 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1197 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1198 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1199 // meshes are already scaled by the meshmerizer
1200 _scale = new OMV.Vector3(1f, 1f, 1f);
1201 // DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID);
1202 return;
1203 }
1204
1205 // Callback from convex hull creater with a newly created hull.
1206 // Just add it to the collection of hulls for this shape.
1207 private void HullReturn(ConvexResult result)
1208 {
1209 _hulls.Add(result);
1210 return;
1211 }
1212
1213 // Create an object in Bullet if it has not already been created
1214 // No locking here because this is done when the physics engine is not simulating
1215 // Returns 'true' if an object was actually created.
1216 private bool CreateObject()
1217 {
1218 // this routine is called when objects are rebuilt.
1219
1220 // the mesh or hull must have already been created in Bullet
1221 ShapeData shape;
1222 FillShapeInfo(out shape);
1223 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1224 bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
1225
1226 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1227 Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
1228
1229 return ret;
1230 }
1231
1232 // Copy prim's info into the BulletSim shape description structure 1202 // Copy prim's info into the BulletSim shape description structure
1233 public void FillShapeInfo(out ShapeData shape) 1203 public void FillShapeInfo(out ShapeData shape)
1234 { 1204 {
1235 shape.ID = _localID; 1205 shape.ID = LocalID;
1236 shape.Type = _shapeType; 1206 shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
1237 shape.Position = _position; 1207 shape.Position = _position;
1238 shape.Rotation = _orientation; 1208 shape.Rotation = _orientation;
1239 shape.Velocity = _velocity; 1209 shape.Velocity = _velocity;
1240 shape.Scale = _scale; 1210 shape.Scale = _scale;
1241 shape.Mass = _isPhysical ? _mass : 0f; 1211 shape.Mass = _isPhysical ? _mass : 0f;
1242 shape.Buoyancy = _buoyancy; 1212 shape.Buoyancy = _buoyancy;
1243 shape.HullKey = _hullKey; 1213 shape.HullKey = 0;
1244 shape.MeshKey = _meshKey; 1214 shape.MeshKey = 0;
1245 shape.Friction = _friction; 1215 shape.Friction = _friction;
1246 shape.Restitution = _restitution; 1216 shape.Restitution = _restitution;
1247 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1217 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1248 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1218 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1219 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1220 shape.Size = _size;
1249 } 1221 }
1250
1251
1252 // Rebuild the geometry and object. 1222 // Rebuild the geometry and object.
1253 // This is called when the shape changes so we need to recreate the mesh/hull. 1223 // This is called when the shape changes so we need to recreate the mesh/hull.
1254 // No locking here because this is done when the physics engine is not simulating 1224 // Called at taint-time!!!
1255 private void RecreateGeomAndObject() 1225 private void CreateGeomAndObject(bool forceRebuild)
1256 { 1226 {
1257 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); 1227 ShapeData shapeData;
1258 if (CreateGeom(true)) 1228 FillShapeInfo(out shapeData);
1259 CreateObject(); 1229
1230 // If this prim is part of a linkset, we must remove and restore the physical
1231 // links of the body is rebuilt.
1232 bool needToRestoreLinkset = false;
1233
1234 // Create the correct physical representation for this type of object.
1235 // Updates BSBody and BSShape with the new information.
1236 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1237 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs,
1238 null, delegate(BulletBody dBody)
1239 {
1240 // Called if the current prim body is about to be destroyed.
1241 // Remove all the physical dependencies on the old body.
1242 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1243 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1244 });
1245
1246 if (needToRestoreLinkset)
1247 {
1248 // If physical body dependencies were removed, restore them
1249 Linkset.RestoreBodyDependencies(this);
1250 }
1251
1252 // Make sure the properties are set on the new object
1253 UpdatePhysicalParameters();
1260 return; 1254 return;
1261 } 1255 }
1262 1256
@@ -1277,7 +1271,7 @@ public sealed class BSPrim : PhysicsActor
1277 const float ACCELERATION_TOLERANCE = 0.01f; 1271 const float ACCELERATION_TOLERANCE = 0.01f;
1278 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1272 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1279 1273
1280 public void UpdateProperties(EntityProperties entprop) 1274 public override void UpdateProperties(EntityProperties entprop)
1281 { 1275 {
1282 /* 1276 /*
1283 UpdatedProperties changed = 0; 1277 UpdatedProperties changed = 0;
@@ -1325,7 +1319,7 @@ public sealed class BSPrim : PhysicsActor
1325 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1319 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1326 1320
1327 // Updates only for individual prims and for the root object of a linkset. 1321 // Updates only for individual prims and for the root object of a linkset.
1328 if (_linkset.IsRoot(this)) 1322 if (Linkset.IsRoot(this))
1329 { 1323 {
1330 // Assign to the local variables so the normal set action does not happen 1324 // Assign to the local variables so the normal set action does not happen
1331 _position = entprop.Position; 1325 _position = entprop.Position;
@@ -1334,69 +1328,26 @@ public sealed class BSPrim : PhysicsActor
1334 _acceleration = entprop.Acceleration; 1328 _acceleration = entprop.Acceleration;
1335 _rotationalVelocity = entprop.RotationalVelocity; 1329 _rotationalVelocity = entprop.RotationalVelocity;
1336 1330
1337 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", 1331 PositionSanityCheck2(true);
1338 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1332
1339 // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1333 Linkset.UpdateProperties(this);
1340 // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1334
1335 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1336 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1337
1338 // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr);
1341 1339
1342 base.RequestPhysicsterseUpdate(); 1340 base.RequestPhysicsterseUpdate();
1343 } 1341 }
1344 /* 1342 /*
1345 else 1343 else
1346 { 1344 {
1347 // For debugging, we also report the movement of children 1345 // For debugging, report the movement of children
1348 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1346 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1349 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1347 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1350 entprop.Acceleration, entprop.RotationalVelocity); 1348 entprop.Acceleration, entprop.RotationalVelocity);
1351 } 1349 }
1352 */ 1350 */
1353 } 1351 }
1354
1355 // I've collided with something
1356 CollisionEventUpdate collisionCollection;
1357 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1358 {
1359 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1360
1361 // The following lines make IsColliding() and IsCollidingGround() work
1362 _collidingStep = _scene.SimulationStep;
1363 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1364 {
1365 _collidingGroundStep = _scene.SimulationStep;
1366 }
1367
1368 // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
1369
1370 // if someone is subscribed to collision events....
1371 if (_subscribedEventsMs != 0) {
1372 // throttle the collisions to the number of milliseconds specified in the subscription
1373 int nowTime = _scene.SimulationNowTime;
1374 if (nowTime >= _nextCollisionOkTime) {
1375 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
1376
1377 if (collisionCollection == null)
1378 collisionCollection = new CollisionEventUpdate();
1379 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1380 }
1381 }
1382 }
1383
1384 // The scene is telling us it's time to pass our collected collisions into the simulator
1385 public void SendCollisions()
1386 {
1387 if (collisionCollection != null && collisionCollection.Count > 0)
1388 {
1389 base.SendCollisionUpdate(collisionCollection);
1390 // The collisionCollection structure is passed around in the simulator.
1391 // Make sure we don't have a handle to that one and that a new one is used next time.
1392 collisionCollection = null;
1393 }
1394 }
1395
1396 // Invoke the detailed logger and output something if it's enabled.
1397 private void DetailLog(string msg, params Object[] args)
1398 {
1399 Scene.PhysicsLogging.Write(msg, args);
1400 }
1401} 1352}
1402} 1353}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..2c3c481 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,33 +39,27 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Debug linkset 42// Test sculpties (verified that they don't work)
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 43// Compute physics FPS reasonably
47// Based on material, set density and friction 44// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
52// At the moment, physical and phantom causes object to drop through the terrain 48// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 49// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
56// Should prim.link() and prim.delink() membership checking happen at taint time? 53// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root. 54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
61// Implement LockAngularMotion 56// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
63// Does NeedsMeshing() really need to exclude all the different shapes?
64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
65// Add PID movement operations. What does ScenePresence.MoveToTarget do? 59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 60// Check terrain size. 128 or 127?
67// Raycast 61// Raycast
68// 62//
69namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
70{ 64{
71public class BSScene : PhysicsScene, IPhysicsParameters 65public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,62 +67,56 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
75 69
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 70 // The name of the region we're working for.
71 public string RegionName { get; private set; }
77 72
78 public string BulletSimVersion = "?"; 73 public string BulletSimVersion = "?";
79 74
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 75 public Dictionary<uint, BSPhysObject> PhysObjects;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 76 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
84 private List<BSPrim> m_vehicles = new List<BSPrim>();
85 private float[] m_heightMap;
86 private float m_waterLevel;
87 private uint m_worldID;
88 public uint WorldID { get { return m_worldID; } }
89 77
90 // let my minuions use my logger 78 // Keeping track of the objects with collisions so we can report begin and end of a collision
91 public ILog Logger { get { return m_log; } } 79 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
80 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
92 84
93 private bool m_initialized = false; 85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
94 88
95 private int m_detailedStatsStep = 0; 89 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } }
96 91
97 public IMesher mesher; 92 public IMesher mesher;
98 private float m_meshLOD; 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 94 public float MeshLOD { get; private set; }
100 { 95 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 96 public float MeshMegaPrimThreshold { get; private set; }
102 } 97 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 98
109 private BulletSim m_worldSim; 99 public uint WorldID { get; private set; }
110 public BulletSim World 100 public BulletSim World { get; private set; }
111 {
112 get { return m_worldSim; }
113 }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119 101
102 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; }
104
105 // Simulation parameters
120 private int m_maxSubSteps; 106 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
124 110 private int m_taintsToProcessPerStep;
125 public float LastSimulatedTimestep { get; private set; }
126 111
127 // A value of the time now so all the collision and update routines do not have to get their own 112 // A value of the time now so all the collision and update routines do not have to get their own
128 // Set to 'now' just before all the prims and actors are called for collisions and updates 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
129 private int m_simulationNowTime; 114 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 115
116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false;
131 118
119 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 120 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 121 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 122 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +125,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 125 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 126 private GCHandle m_updateArrayPinnedHandle;
139 127
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 128 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
141 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 129 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
130 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
142 131
143 public float PID_D { get; private set; } // derivative 132 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 133 public float PID_P { get; private set; } // proportional
145 134
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 135 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 136 public const uint GROUNDPLANE_ID = 1;
137 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
138
139 private float m_waterLevel;
140 public BSTerrainManager TerrainManager { get; private set; }
148 141
149 public ConfigurationParameters Params 142 public ConfigurationParameters Params
150 { 143 {
@@ -154,13 +147,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 147 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 148 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 149 }
157 150 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 151 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 152 {
161 get { return m_maximumObjectMass; } 153 get { return Params.gravity; }
162 } 154 }
163 155
156 public float MaximumObjectMass { get; private set; }
157
158 // When functions in the unmanaged code must be called, it is only
159 // done at a known time just before the simulation step. The taint
160 // system saves all these function calls and executes them in
161 // order before the simulation.
164 public delegate void TaintCallback(); 162 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 163 private struct TaintCallbackEntry
166 { 164 {
@@ -172,15 +170,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 170 callback = c;
173 } 171 }
174 } 172 }
173 private Object _taintLock = new Object(); // lock for using the next object
175 private List<TaintCallbackEntry> _taintedObjects; 174 private List<TaintCallbackEntry> _taintedObjects;
176 private Object _taintLock = new Object();
177 175
178 // A pointer to an instance if this structure is passed to the C++ code 176 // A pointer to an instance if this structure is passed to the C++ code
177 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 178 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 179 GCHandle m_paramsHandle;
181 180
182 public bool ShouldDebugLog { get; private set; } 181 // Handle to the callback used by the unmanaged code to call into the managed code.
183 182 // Used for debug logging.
183 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 185
186 // Sometimes you just have to log everything. 186 // Sometimes you just have to log everything.
@@ -189,17 +189,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 189 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 190 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 191 private int m_physicsLoggingFileMinutes;
192 // 'true' of the vehicle code is to log lots of details
193 public bool VehicleLoggingEnabled { get; private set; }
192 194
193 private bool m_vehicleLoggingEnabled; 195 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 196 public BSScene(string identifier)
197 { 197 {
198 m_initialized = false; 198 m_initialized = false;
199 // we are passed the name of the region we're working for.
200 RegionName = identifier;
199 } 201 }
200 202
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 203 public override void Initialise(IMesher meshmerizer, IConfigSource config)
202 { 204 {
205 mesher = meshmerizer;
206 _taintedObjects = new List<TaintCallbackEntry>();
207 PhysObjects = new Dictionary<uint, BSPhysObject>();
208 Shapes = new BSShapeCollection(this);
209
203 // Allocate pinned memory to pass parameters. 210 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 211 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 212 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +222,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 222
216 // Enable very detailed logging. 223 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 224 // By creating an empty logger when not logging, the log message invocation code
218 // can be left in and every call doesn't have to check for null. 225 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 226 if (m_physicsLoggingEnabled)
220 { 227 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 228 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,38 +232,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 232 PhysicsLogging = new Logging.LogWriter();
226 } 233 }
227 234
228 // Get the version of the DLL 235 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 236 m_DebugLogCallbackHandle = null;
230 // BulletSimVersion = BulletSimAPI.GetVersion();
231 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
232
233 // if Debug, enable logging from the unmanaged code
234 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 237 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 238 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 239 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 240 if (PhysicsLogging.Enabled)
241 // The handle is saved in a variable to make sure it doesn't get freed after this call
238 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); 242 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 243 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 244 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
241 // the handle is saved in a variable to make sure it doesn't get freed after this call
242 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
243 } 245 }
244 246
245 _taintedObjects = new List<TaintCallbackEntry>(); 247 // Get the version of the DLL
248 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
249 // BulletSimVersion = BulletSimAPI.GetVersion();
250 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 251
247 mesher = meshmerizer; 252 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 253 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 254 // Bullet actually doesn't care about the extents of the simulated
255 // area. It tracks active objects no matter where they are.
256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 257
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 259 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
262 m_DebugLogCallbackHandle);
255 263
256 // Initialization to support the transition to a new API which puts most of the logic 264 // Initialization to support the transition to a new API which puts most of the logic
257 // into the C# code so it is easier to modify and add to. 265 // into the C# code so it is easier to modify and add to.
258 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID)); 266 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
259 m_constraintCollection = new BSConstraintCollection(World); 267
268 Constraints = new BSConstraintCollection(World);
269
270 TerrainManager = new BSTerrainManager(this);
271 TerrainManager.CreateInitialGroundPlaneAndTerrain();
260 272
261 m_initialized = true; 273 m_initialized = true;
262 } 274 }
@@ -281,10 +293,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 293 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 294 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 295 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 296 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 297 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 298 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 299 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
300
301 // Do any replacements in the parameters
302 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 303 }
289 } 304 }
290 } 305 }
@@ -309,12 +324,50 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 324 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 325 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 326 }
312 327
313 // Called directly from unmanaged code so don't do much 328 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 329 private void BulletLoggerPhysLog(string msg)
315 { 330 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 331 DetailLog("[BULLETS UNMANAGED]:" + msg);
332 }
333
334 public override void Dispose()
335 {
336 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
337
338 // make sure no stepping happens while we're deleting stuff
339 m_initialized = false;
340
341 TerrainManager.ReleaseGroundPlaneAndTerrain();
342
343 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
344 {
345 kvp.Value.Destroy();
346 }
347 PhysObjects.Clear();
348
349 // Now that the prims are all cleaned up, there should be no constraints left
350 if (Constraints != null)
351 {
352 Constraints.Dispose();
353 Constraints = null;
354 }
355
356 if (Shapes != null)
357 {
358 Shapes.Dispose();
359 Shapes = null;
360 }
361
362 // Anything left in the unmanaged code should be cleaned out
363 BulletSimAPI.Shutdown(WorldID);
364
365 // Not logging any more
366 PhysicsLogging.Close();
317 } 367 }
368 #endregion // Construction and Initialization
369
370 #region Prim and Avatar addition and removal
318 371
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 372 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 373 {
@@ -329,7 +382,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 382 if (!m_initialized) return null;
330 383
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 384 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 385 lock (PhysObjects) PhysObjects.Add(localID, actor);
386
387 // TODO: Remove kludge someday.
388 // We must generate a collision for avatars whether they collide or not.
389 // This is required by OpenSim to update avatar animations, etc.
390 lock (m_avatars) m_avatars.Add(actor);
391
333 return actor; 392 return actor;
334 } 393 }
335 394
@@ -344,7 +403,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 403 {
345 try 404 try
346 { 405 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 406 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
407 // Remove kludge someday
408 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 409 }
349 catch (Exception e) 410 catch (Exception e)
350 { 411 {
@@ -362,11 +423,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 423 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 424 if (bsprim != null)
364 { 425 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 426 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 427 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 428 try
368 { 429 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 430 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 431 }
371 catch (Exception e) 432 catch (Exception e)
372 { 433 {
@@ -388,18 +449,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 449
389 if (!m_initialized) return null; 450 if (!m_initialized) return null;
390 451
391 // DetailLog("{0},AddPrimShape,call", localID); 452 DetailLog("{0},AddPrimShape,call", localID);
392 453
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 454 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 455 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 456 return prim;
396 } 457 }
397 458
398 // This is a call from the simulator saying that some physical property has been updated. 459 // This is a call from the simulator saying that some physical property has been updated.
399 // The BulletSim driver senses the changing of relevant properties so this taint 460 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 461 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 462 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 463
464 #endregion // Prim and Avatar addition and removal
465
466 #region Simulation
403 // Simulate one timestep 467 // Simulate one timestep
404 public override float Simulate(float timeStep) 468 public override float Simulate(float timeStep)
405 { 469 {
@@ -408,34 +472,46 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 472 int collidersCount = 0;
409 IntPtr collidersPtr; 473 IntPtr collidersPtr;
410 474
411 LastSimulatedTimestep = timeStep; 475 int beforeTime = 0;
476 int simTime = 0;
412 477
413 // prevent simulation until we've been initialized 478 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 479 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 480
418 // update the prim states while we know the physics engine is not busy 481 // update the prim states while we know the physics engine is not busy
482 int numTaints = _taintedObjects.Count;
419 ProcessTaints(); 483 ProcessTaints();
420 484
421 // Some of the prims operate with special vehicle properties 485 // Some of the prims operate with special vehicle properties
422 ProcessVehicles(timeStep); 486 ProcessVehicles(timeStep);
487 numTaints += _taintedObjects.Count;
423 ProcessTaints(); // the vehicles might have added taints 488 ProcessTaints(); // the vehicles might have added taints
424 489
425 // step the physical world one interval 490 // step the physical world one interval
426 m_simulationStep++; 491 m_simulationStep++;
427 int numSubSteps = 0; 492 int numSubSteps = 0;
493
494 // DEBUG
495 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
496
428 try 497 try
429 { 498 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 499 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
500
501 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 502 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 503
504 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
505 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
506 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
433 } 507 }
434 catch (Exception e) 508 catch (Exception e)
435 { 509 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 510 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
437 // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 511 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 512 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
513 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
514 updatedEntityCount = 0;
439 collidersCount = 0; 515 collidersCount = 0;
440 } 516 }
441 517
@@ -443,7 +519,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
443 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 519 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 520
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 521 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 522 SimulationNowTime = Util.EnvironmentTickCount();
447 523
448 // If there were collisions, process them by sending the event to the prim. 524 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 525 // Collisions must be processed before updates.
@@ -460,21 +536,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
460 } 536 }
461 } 537 }
462 538
539 // This is a kludge to get avatar movement updates.
540 // the simulator expects collisions for avatars even if there are have been no collisions. This updates
541 // avatar animations and stuff.
542 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
543 foreach (BSPhysObject bsp in m_avatars)
544 bsp.SendCollisions();
545
463 // The above SendCollision's batch up the collisions on the objects. 546 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 547 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 548 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 549 {
467 m_primsWithCollisions.Clear(); 550 foreach (BSPhysObject bsp in ObjectsWithCollisions)
551 if (!m_avatars.Contains(bsp)) // don't call avatars twice
552 if (!bsp.SendCollisions())
553 {
554 // If the object is done colliding, see that it's removed from the colliding list
555 ObjectsWithNoMoreCollisions.Add(bsp);
556 }
557 }
468 558
469 // This is a kludge to get avatar movement updated. 559 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
470 // Don't send collisions only if there were collisions -- send everytime. 560 // Not done above because it is inside an iteration of ObjectWithCollisions.
471 // ODE sends collisions even if there are none and this is used to update 561 if (ObjectsWithNoMoreCollisions.Count > 0)
472 // avatar animations and stuff. 562 {
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 563 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
474 // bsc.SendCollisions(); 564 ObjectsWithCollisions.Remove(po);
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 565 ObjectsWithNoMoreCollisions.Clear();
476 kvp.Value.SendCollisions(); 566 }
477 m_avatarsWithCollisions.Clear();
478 567
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 568 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 569 if (updatedEntityCount > 0)
@@ -482,145 +571,98 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 571 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 572 {
484 EntityProperties entprop = m_updateArray[ii]; 573 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 574 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 575 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 {
488 prim.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 { 576 {
494 actor.UpdateProperties(entprop); 577 pobj.UpdateProperties(entprop);
495 continue;
496 } 578 }
497 } 579 }
498 } 580 }
499 581
500 // If enabled, call into the physics engine to dump statistics 582 // The physics engine returns the number of milliseconds it simulated this call.
501 if (m_detailedStatsStep > 0) 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
502 { 584 // We multiply by 45 to give a recognizable running rate (45 or less).
503 if ((m_simulationStep % m_detailedStatsStep) == 0) 585 return numSubSteps * m_fixedTimeStep * 1000 * 45;
504 { 586 // return timeStep * 1000 * 45;
505 BulletSimAPI.DumpBulletStatistics();
506 }
507 }
508
509 // this is a waste since the outside routine also calcuates the physics simulation
510 // period. TODO: There should be a way of computing physics frames from simulator computation.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
512 // return (timeStep * (float)simulateTotalTime);
513
514 // TODO: FIX THIS: fps calculation possibly wrong.
515 // This calculation says 1/timeStep is the ideal frame rate. Any time added to
516 // that by the physics simulation gives a slower frame rate.
517 long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
518 if (totalSimulationTime >= timeStep)
519 return 0;
520 return 1f / (timeStep + totalSimulationTime);
521 } 587 }
522 588
523 // Something has collided 589 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 590 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 591 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 592 if (localID <= TerrainManager.HighestTerrainID)
527 { 593 {
528 return; // don't send collisions to the terrain 594 return; // don't send collisions to the terrain
529 } 595 }
530 596
531 ActorTypes type = ActorTypes.Prim; 597 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 598 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 599 {
534 else if (m_avatars.ContainsKey(collidingWith)) 600 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 601 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
536
537 BSPrim prim;
538 if (m_prims.TryGetValue(localID, out prim)) {
539 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
540 m_primsWithCollisions.Add(prim);
541 return; 602 return;
542 } 603 }
543 BSCharacter actor; 604
544 if (m_avatars.TryGetValue(localID, out actor)) { 605 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
545 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 606 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 607 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 608
609 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
610
611 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
612 {
613 // If a collision was posted, remember to send it to the simulator
614 ObjectsWithCollisions.Add(collider);
548 } 615 }
616
549 return; 617 return;
550 } 618 }
551 619
552 public override void GetResults() { } 620 #endregion // Simulation
553 621
554 public override void SetTerrain(float[] heightMap) { 622 public override void GetResults() { }
555 m_heightMap = heightMap;
556 this.TaintedObject("BSScene.SetTerrain", delegate()
557 {
558 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
559 });
560 }
561 623
562 // Someday we will have complex terrain with caves and tunnels 624 #region Terrain
563 // For the moment, it's flat and convex
564 public float GetTerrainHeightAtXYZ(Vector3 loc)
565 {
566 return GetTerrainHeightAtXY(loc.X, loc.Y);
567 }
568 625
569 public float GetTerrainHeightAtXY(float tX, float tY) 626 public override void SetTerrain(float[] heightMap) {
570 { 627 TerrainManager.SetTerrain(heightMap);
571 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
572 return 30;
573 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
574 } 628 }
575 629
576 public override void SetWaterLevel(float baseheight) 630 public override void SetWaterLevel(float baseheight)
577 { 631 {
578 m_waterLevel = baseheight; 632 m_waterLevel = baseheight;
579 // TODO: pass to physics engine so things will float?
580 } 633 }
581 public float GetWaterLevel() 634 // Someday....
635 public float GetWaterLevelAtXYZ(Vector3 loc)
582 { 636 {
583 return m_waterLevel; 637 return m_waterLevel;
584 } 638 }
585 639
586 public override void DeleteTerrain() 640 public override void DeleteTerrain()
587 { 641 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 642 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
589 } 643 }
590 644
591 public override void Dispose() 645 // Although no one seems to check this, I do support combining.
646 public override bool SupportsCombining()
592 { 647 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 648 return TerrainManager.SupportsCombining();
594 649 }
595 // make sure no stepping happens while we're deleting stuff 650 // This call says I am a child to region zero in a mega-region. 'pScene' is that
596 m_initialized = false; 651 // of region zero, 'offset' is my offset from regions zero's origin, and
597 652 // 'extents' is the largest XY that is handled in my region.
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 653 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
599 { 654 {
600 kvp.Value.Destroy(); 655 TerrainManager.Combine(pScene, offset, extents);
601 } 656 }
602 m_avatars.Clear();
603
604 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
605 {
606 kvp.Value.Destroy();
607 }
608 m_prims.Clear();
609
610 // Now that the prims are all cleaned up, there should be no constraints left
611 if (m_constraintCollection != null)
612 {
613 m_constraintCollection.Dispose();
614 m_constraintCollection = null;
615 }
616
617 // Anything left in the unmanaged code should be cleaned out
618 BulletSimAPI.Shutdown(WorldID);
619 657
620 // Not logging any more 658 // Unhook all the combining that I know about.
621 PhysicsLogging.Close(); 659 public override void UnCombine(PhysicsScene pScene)
660 {
661 TerrainManager.UnCombine(pScene);
622 } 662 }
623 663
664 #endregion // Terrain
665
624 public override Dictionary<uint, float> GetTopColliders() 666 public override Dictionary<uint, float> GetTopColliders()
625 { 667 {
626 return new Dictionary<uint, float>(); 668 return new Dictionary<uint, float>();
@@ -628,121 +670,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
628 670
629 public override bool IsThreaded { get { return false; } } 671 public override bool IsThreaded { get { return false; } }
630 672
631 /// <summary>
632 /// Routine to figure out if we need to mesh this prim with our mesher
633 /// </summary>
634 /// <param name="pbs"></param>
635 /// <returns>true if the prim needs meshing</returns>
636 public bool NeedsMeshing(PrimitiveBaseShape pbs)
637 {
638 // most of this is redundant now as the mesher will return null if it cant mesh a prim
639 // but we still need to check for sculptie meshing being enabled so this is the most
640 // convenient place to do it for now...
641
642 // int iPropertiesNotSupportedDefault = 0;
643
644 if (pbs.SculptEntry && !_meshSculptedPrim)
645 {
646 // Render sculpties as boxes
647 return false;
648 }
649
650 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
651 // can use an internal representation for the prim
652 if (!_forceSimplePrimMeshing)
653 {
654 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
655 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
656 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
657 {
658
659 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
660 && pbs.ProfileHollow == 0
661 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
662 && pbs.PathBegin == 0 && pbs.PathEnd == 0
663 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
664 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
665 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
666 {
667 return false;
668 }
669 }
670 }
671
672 /* TODO: verify that the mesher will now do all these shapes
673 if (pbs.ProfileHollow != 0)
674 iPropertiesNotSupportedDefault++;
675
676 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
677 iPropertiesNotSupportedDefault++;
678
679 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
680 iPropertiesNotSupportedDefault++;
681
682 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
683 iPropertiesNotSupportedDefault++;
684
685 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
686 iPropertiesNotSupportedDefault++;
687
688 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
689 iPropertiesNotSupportedDefault++;
690
691 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
692 iPropertiesNotSupportedDefault++;
693
694 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))
695 iPropertiesNotSupportedDefault++;
696
697 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
698 iPropertiesNotSupportedDefault++;
699
700 // test for torus
701 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
702 {
703 if (pbs.PathCurve == (byte)Extrusion.Curve1)
704 {
705 iPropertiesNotSupportedDefault++;
706 }
707 }
708 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
709 {
710 if (pbs.PathCurve == (byte)Extrusion.Straight)
711 {
712 iPropertiesNotSupportedDefault++;
713 }
714 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
715 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
716 {
717 iPropertiesNotSupportedDefault++;
718 }
719 }
720 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
721 {
722 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
723 {
724 iPropertiesNotSupportedDefault++;
725 }
726 }
727 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
728 {
729 if (pbs.PathCurve == (byte)Extrusion.Straight)
730 {
731 iPropertiesNotSupportedDefault++;
732 }
733 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
734 {
735 iPropertiesNotSupportedDefault++;
736 }
737 }
738 if (iPropertiesNotSupportedDefault == 0)
739 {
740 return false;
741 }
742 */
743 return true;
744 }
745
746 // Calls to the PhysicsActors can't directly call into the physics engine 673 // Calls to the PhysicsActors can't directly call into the physics engine
747 // because it might be busy. We delay changes to a known time. 674 // because it might be busy. We delay changes to a known time.
748 // We rely on C#'s closure to save and restore the context for the delegate. 675 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -751,7 +678,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
751 if (!m_initialized) return; 678 if (!m_initialized) return;
752 679
753 lock (_taintLock) 680 lock (_taintLock)
681 {
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 682 _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
683 }
684
755 return; 685 return;
756 } 686 }
757 687
@@ -763,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
763 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
764 { 694 {
765 // swizzle a new list into the list location so we can process what's there 695 // swizzle a new list into the list location so we can process what's there
696 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0)
699 {
700 bool gotOne = false;
701 lock (_taintLock)
702 {
703 if (_taintedObjects.Count > 0)
704 {
705 oneCallback = _taintedObjects[0];
706 _taintedObjects.RemoveAt(0);
707 gotOne = true;
708 }
709 }
710 if (gotOne)
711 {
712 try
713 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
715 oneCallback.callback();
716 }
717 catch (Exception e)
718 {
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 }
721 }
722 }
723 /*
724 // swizzle a new list into the list location so we can process what's there
766 List<TaintCallbackEntry> oldList; 725 List<TaintCallbackEntry> oldList;
767 lock (_taintLock) 726 lock (_taintLock)
768 { 727 {
@@ -774,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
774 { 733 {
775 try 734 try
776 { 735 {
736 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
777 tcbe.callback(); 737 tcbe.callback();
778 } 738 }
779 catch (Exception e) 739 catch (Exception e)
@@ -782,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
782 } 742 }
783 } 743 }
784 oldList.Clear(); 744 oldList.Clear();
745 */
785 } 746 }
786 } 747 }
787 748
@@ -789,13 +750,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
789 750
790 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 751 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
791 { 752 {
792 if (newType == Vehicle.TYPE_NONE) 753 RemoveVehiclePrim(vehic);
793 { 754 if (newType != Vehicle.TYPE_NONE)
794 RemoveVehiclePrim(vehic);
795 }
796 else
797 { 755 {
798 // make it so the scene will call us each tick to do vehicle things 756 // make it so the scene will call us each tick to do vehicle things
799 AddVehiclePrim(vehic); 757 AddVehiclePrim(vehic);
800 } 758 }
801 } 759 }
@@ -827,17 +785,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
827 } 785 }
828 786
829 // Some prims have extra vehicle actions 787 // Some prims have extra vehicle actions
830 // no locking because only called when physics engine is not busy 788 // Called at taint time!
831 private void ProcessVehicles(float timeStep) 789 private void ProcessVehicles(float timeStep)
832 { 790 {
833 foreach (BSPrim prim in m_vehicles) 791 foreach (BSPhysObject pobj in m_vehicles)
834 { 792 {
835 prim.StepVehicle(timeStep); 793 pobj.StepVehicle(timeStep);
836 } 794 }
837 } 795 }
838 #endregion Vehicles 796 #endregion Vehicles
839 797
840 #region Parameters 798 #region INI and command line parameter processing
841 799
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 801 delegate float ParamGet(BSScene scene);
@@ -869,7 +827,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 827 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 828 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 829 // Parameter values are floats. Booleans are converted to a floating value.
872 // 830 //
873 // A ParameterDefn() takes the following parameters: 831 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 832 // -- the text name of the parameter. This is used for console input and ini file.
875 // -- a short text description of the parameter. This shows up in the console listing. 833 // -- a short text description of the parameter. This shows up in the console listing.
@@ -888,25 +846,40 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 846 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 847 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 848 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 849 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 850 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 851 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 852 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 853 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 854 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 855 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 856 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
857 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
858 ConfigurationParameters.numericTrue,
859 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
860 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
861 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
899 862
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 863 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 864 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 865 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 866 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 867 (s,p,l,v) => { s.MeshLOD = v; } ),
905 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", 868 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
869 16f,
870 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
871 (s) => { return s.MeshMegaPrimLOD; },
872 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
873 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
874 10f,
875 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
876 (s) => { return s.MeshMegaPrimThreshold; },
877 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
878 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 879 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 880 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 881 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 882 (s,p,l,v) => { s.SculptLOD = v; } ),
910 883
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 884 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 885 10f,
@@ -928,11 +901,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
928 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 901 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
929 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 902 (s) => { return (float)s.m_maxUpdatesPerFrame; },
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 903 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
904 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
905 100f,
906 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
907 (s) => { return (float)s.m_taintsToProcessPerStep; },
908 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 909 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 910 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 911 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 912 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 913 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 914
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 915 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 916 2200f,
@@ -976,42 +954,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
976 0f, 954 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 955 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 956 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 957 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
980 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 958 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 959 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 960 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 961 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 962 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
985 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 963 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 964 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 965 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 966 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 967 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
990 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 968 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 969 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 971 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
995 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 973 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 974 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 975 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 976 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 977 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
1000 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 978 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 979 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 980 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 981 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 982 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 983 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 984 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 985 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 986 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 987 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 988 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 989 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 990 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 991 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 992 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
1015 993
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 994 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 995 0.5f,
@@ -1029,44 +1007,44 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1029 (s) => { return s.m_params[0].terrainRestitution; }, 1007 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1008 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
1031 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1009 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 1010 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1011 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 1012 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 1013 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1036 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 1014 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 1015 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1016 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 1017 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 1018 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 1019 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 1020 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1021 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 1022 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1023 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1046 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 1024 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
1047 0.37f, 1025 0.37f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1026 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1027 (s) => { return s.m_params[0].avatarCapsuleRadius; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1028 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
1051 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1029 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 1030 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1031 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1032 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1033 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1056 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 1034 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1035 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1036 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1037 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1038 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1039
1062 1040
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1041 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1064 0f, // zero to disable 1042 0f,
1065 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, 1043 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, 1044 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1067 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), 1045 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1068 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", 1046 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1069 0f, // zero to disable 1047 0f,
1070 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, 1048 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, 1049 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1072 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), 1050 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
@@ -1081,12 +1059,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1081 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, 1059 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1082 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), 1060 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1083 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", 1061 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1084 ConfigurationParameters.numericFalse, 1062 ConfigurationParameters.numericTrue,
1085 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1063 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1086 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1064 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1065 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1066 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1067 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1068 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1091 (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, 1069 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1070 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1121,28 +1099,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1099 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1100 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1101 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1124 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", 1102 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1103 0.001f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1104 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1105 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1106 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1129 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1107 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1130 0.2f, 1108 0.8f,
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1109 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1110 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1111 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1112 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1113 40,
1114 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1115 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1116 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1117
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1118 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1119 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1120 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1121 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1122 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1140 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1141 ConfigurationParameters.numericFalse,
1142 (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1143 (s) => { return s.NumericBool(s.ShouldDebugLog); },
1144 (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ),
1145
1146 }; 1123 };
1147 1124
1148 // Convert a boolean to our numeric true and false values 1125 // Convert a boolean to our numeric true and false values
@@ -1200,11 +1177,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1177
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1178 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1179
1180 // This creates an array in the correct format for returning the list of
1181 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1182 private void BuildParameterTable()
1204 { 1183 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1184 if (SettableParameters.Length < ParameterDefinitions.Length)
1206 { 1185 {
1207
1208 List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); 1186 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1209 for (int ii = 0; ii < ParameterDefinitions.Length; ii++) 1187 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1210 { 1188 {
@@ -1250,18 +1228,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1250 } 1228 }
1251 1229
1252 // check to see if we are updating a parameter for a particular or all of the prims 1230 // check to see if we are updating a parameter for a particular or all of the prims
1253 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) 1231 protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
1254 {
1255 List<uint> operateOn;
1256 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
1257 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1258 }
1259
1260 // check to see if we are updating a parameter for a particular or all of the avatars
1261 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
1262 { 1232 {
1263 List<uint> operateOn; 1233 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); 1234 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val); 1235 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 } 1236 }
1267 1237
@@ -1284,11 +1254,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1254 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs) 1255 foreach (uint lID in objectIDs)
1286 { 1256 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); 1257 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1288 } 1258 }
1289 }); 1259 });
1290 break; 1260 break;
1291 default: 1261 default:
1292 // setting only one localID 1262 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1263 TaintedUpdateParameter(parm, localID, val);
1294 break; 1264 break;
@@ -1302,7 +1272,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1302 string xparm = parm.ToLower(); 1272 string xparm = parm.ToLower();
1303 float xval = val; 1273 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1274 TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1275 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
1306 }); 1276 });
1307 } 1277 }
1308 1278
@@ -1330,6 +1300,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1330 public void DetailLog(string msg, params Object[] args) 1300 public void DetailLog(string msg, params Object[] args)
1331 { 1301 {
1332 PhysicsLogging.Write(msg, args); 1302 PhysicsLogging.Write(msg, args);
1303 // Add the Flush() if debugging crashes to get all the messages written out.
1304 // PhysicsLogging.Flush();
1333 } 1305 }
1334 // used to fill in the LocalID when there isn't one 1306 // used to fill in the LocalID when there isn't one
1335 public const string DetailLogZero = "0000000000"; 1307 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
new file mode 100755
index 0000000..d189f1d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -0,0 +1,756 @@
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 copyrightD
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSShapeCollection : IDisposable
38{
39 // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 protected BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public IntPtr ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 }
52
53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
55 private struct HullDesc
56 {
57 public IntPtr ptr;
58 public int referenceCount;
59 public DateTime lastReferenced;
60 }
61
62 private struct BodyDesc
63 {
64 public IntPtr ptr;
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
71 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73
74 public BSShapeCollection(BSScene physScene)
75 {
76 PhysicsScene = physScene;
77 }
78
79 public void Dispose()
80 {
81 // TODO!!!!!!!!!
82 }
83
84 // Callbacks called just before either the body or shape is destroyed.
85 // Mostly used for changing bodies out from under Linksets.
86 // Useful for other cases where parameters need saving.
87 // Passing 'null' says no callback.
88 public delegate void ShapeDestructionCallback(BulletShape shape);
89 public delegate void BodyDestructionCallback(BulletBody body);
90
91 // Called to update/change the body and shape for an object.
92 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed.
95 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 {
100 bool ret = false;
101
102 // This lock could probably be pushed down lower but building shouldn't take long
103 lock (m_collectionActivityLock)
104 {
105 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body
111 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
112 prim.BSShape, shapeData, bodyCallback);
113 ret = newGeom || newBody;
114 }
115 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
116 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
117
118 return ret;
119 }
120
121 // Track another user of a body
122 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0.
124 public void ReferenceBody(BulletBody body, bool inTaintTime)
125 {
126 lock (m_collectionActivityLock)
127 {
128 BodyDesc bodyDesc;
129 if (Bodies.TryGetValue(body.ID, out bodyDesc))
130 {
131 bodyDesc.referenceCount++;
132 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
133 }
134 else
135 {
136 // New entry
137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
140 body.ID, body, bodyDesc.referenceCount);
141 BSScene.TaintCallback createOperation = delegate()
142 {
143 if (!BulletSimAPI.IsInWorld2(body.ptr))
144 {
145 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
146 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
147 body.ID, body);
148 }
149 };
150 if (inTaintTime)
151 createOperation();
152 else
153 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
154 }
155 bodyDesc.lastReferenced = System.DateTime.Now;
156 Bodies[body.ID] = bodyDesc;
157 }
158 }
159
160 // Release the usage of a body.
161 // Called when releasing use of a BSBody. BSShape is handled separately.
162 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
163 {
164 if (body.ptr == IntPtr.Zero)
165 return;
166
167 lock (m_collectionActivityLock)
168 {
169 BodyDesc bodyDesc;
170 if (Bodies.TryGetValue(body.ID, out bodyDesc))
171 {
172 bodyDesc.referenceCount--;
173 bodyDesc.lastReferenced = System.DateTime.Now;
174 Bodies[body.ID] = bodyDesc;
175 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
176
177 // If body is no longer being used, free it -- bodies can never be shared.
178 if (bodyDesc.referenceCount == 0)
179 {
180 Bodies.Remove(body.ID);
181 BSScene.TaintCallback removeOperation = delegate()
182 {
183 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
184 body.ID, body.ptr.ToString("X"), inTaintTime);
185 // If the caller needs to know the old body is going away, pass the event up.
186 if (bodyCallback != null) bodyCallback(body);
187
188 // It may have already been removed from the world in which case the next is a NOOP.
189 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
190
191 // Zero any reference to the shape so it is not freed when the body is deleted.
192 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
193 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
194 };
195 // If already in taint-time, do the operations now. Otherwise queue for later.
196 if (inTaintTime)
197 removeOperation();
198 else
199 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
200 }
201 }
202 else
203 {
204 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
205 }
206 }
207 }
208
209 // Track the datastructures and use count for a shape.
210 // When creating a hull, this is called first to reference the mesh
211 // and then again to reference the hull.
212 // Meshes and hulls for the same shape have the same hash key.
213 // NOTE that native shapes are not added to the mesh list or removed.
214 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
215 private bool ReferenceShape(BulletShape shape)
216 {
217 bool ret = false;
218 switch (shape.type)
219 {
220 case ShapeData.PhysicsShapeType.SHAPE_MESH:
221 MeshDesc meshDesc;
222 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
223 {
224 // There is an existing instance of this mesh.
225 meshDesc.referenceCount++;
226 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
228 }
229 else
230 {
231 // This is a new reference to a mesh
232 meshDesc.ptr = shape.ptr;
233 // We keep a reference to the underlying IMesh data so a hull can be built
234 meshDesc.referenceCount = 1;
235 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
236 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
237 ret = true;
238 }
239 meshDesc.lastReferenced = System.DateTime.Now;
240 Meshes[shape.shapeKey] = meshDesc;
241 break;
242 case ShapeData.PhysicsShapeType.SHAPE_HULL:
243 HullDesc hullDesc;
244 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
245 {
246 // There is an existing instance of this hull.
247 hullDesc.referenceCount++;
248 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
249 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
250 }
251 else
252 {
253 // This is a new reference to a hull
254 hullDesc.ptr = shape.ptr;
255 hullDesc.referenceCount = 1;
256 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
257 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
258 ret = true;
259
260 }
261 hullDesc.lastReferenced = System.DateTime.Now;
262 Hulls[shape.shapeKey] = hullDesc;
263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break;
266 default:
267 // Native shapes are not tracked and they don't go into any list
268 break;
269 }
270 return ret;
271 }
272
273 // Release the usage of a shape.
274 // The collisionObject is released since it is a copy of the real collision shape.
275 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
276 {
277 if (shape.ptr == IntPtr.Zero)
278 return;
279
280 BSScene.TaintCallback dereferenceOperation = delegate()
281 {
282 switch (shape.type)
283 {
284 case ShapeData.PhysicsShapeType.SHAPE_HULL:
285 DereferenceHull(shape, shapeCallback);
286 break;
287 case ShapeData.PhysicsShapeType.SHAPE_MESH:
288 DereferenceMesh(shape, shapeCallback);
289 break;
290 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
291 break;
292 default:
293 // Native shapes are not tracked and are released immediately
294 if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
295 {
296 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
297 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
298 if (shapeCallback != null) shapeCallback(shape);
299 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
300 }
301 break;
302 }
303 };
304 if (inTaintTime)
305 {
306 lock (m_collectionActivityLock)
307 {
308 dereferenceOperation();
309 }
310 }
311 else
312 {
313 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
314 }
315 }
316
317 // Count down the reference count for a mesh shape
318 // Called at taint-time.
319 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
320 {
321 MeshDesc meshDesc;
322 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
323 {
324 meshDesc.referenceCount--;
325 // TODO: release the Bullet storage
326 if (shapeCallback != null) shapeCallback(shape);
327 meshDesc.lastReferenced = System.DateTime.Now;
328 Meshes[shape.shapeKey] = meshDesc;
329 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
330 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
331
332 }
333 }
334
335 // Count down the reference count for a hull shape
336 // Called at taint-time.
337 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
338 {
339 HullDesc hullDesc;
340 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
341 {
342 hullDesc.referenceCount--;
343 // TODO: release the Bullet storage (aging old entries?)
344 if (shapeCallback != null) shapeCallback(shape);
345 hullDesc.lastReferenced = System.DateTime.Now;
346 Hulls[shape.shapeKey] = hullDesc;
347 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
348 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
349 }
350 }
351
352 // Create the geometry information in Bullet for later use.
353 // The objects needs a hull if it's physical otherwise a mesh is enough.
354 // No locking here because this is done when we know physics is not simulating.
355 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
356 // Returns 'true' if the geometry was rebuilt.
357 // Called at taint-time!
358 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
359 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
360 {
361 bool ret = false;
362 bool haveShape = false;
363 bool nativeShapePossible = true;
364
365 // If the prim attributes are simple, this could be a simple Bullet native shape
366 if (nativeShapePossible
367 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
368 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
369 && pbs.ProfileHollow == 0
370 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
371 && pbs.PathBegin == 0 && pbs.PathEnd == 0
372 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
373 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
374 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
375 {
376 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
377 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
378 {
379 haveShape = true;
380 if (forceRebuild
381 || prim.Scale != shapeData.Size
382 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
383 )
384 {
385 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
386 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
387 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
388 prim.LocalID, forceRebuild, prim.BSShape);
389 }
390 }
391 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
392 {
393 haveShape = true;
394 if (forceRebuild
395 || prim.Scale != shapeData.Size
396 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
397 )
398 {
399 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
400 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
401 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
402 prim.LocalID, forceRebuild, prim.BSShape);
403 }
404 }
405 }
406 // If a simple shape is not happening, create a mesh and possibly a hull.
407 // Note that if it's a native shape, the check for physical/non-physical is not
408 // made. Native shapes are best used in either case.
409 if (!haveShape)
410 {
411 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
412 {
413 // Update prim.BSShape to reference a hull of this shape.
414 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
415 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
416 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
417 }
418 else
419 {
420 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
421 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
422 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
423 }
424 }
425 return ret;
426 }
427
428 // Creates a native shape and assignes it to prim.BSShape
429 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
430 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
431 ShapeDestructionCallback shapeCallback)
432 {
433 BulletShape newShape;
434
435 shapeData.Type = shapeType;
436 // Bullet native objects are scaled by the Bullet engine so pass the size in
437 prim.Scale = shapeData.Size;
438 shapeData.Scale = shapeData.Size;
439
440 // release any previous shape
441 DereferenceShape(prim.BSShape, true, shapeCallback);
442
443 // Native shapes are always built independently.
444 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
445 newShape.shapeKey = (System.UInt64)shapeKey;
446 newShape.isNativeShape = true;
447
448 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
449 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
450
451 prim.BSShape = newShape;
452 return true;
453 }
454
455 // Builds a mesh shape in the physical world and updates prim.BSShape.
456 // Dereferences previous shape in BSShape and adds a reference for this new shape.
457 // Returns 'true' of a mesh was actually built. Otherwise .
458 // Called at taint-time!
459 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
460 ShapeDestructionCallback shapeCallback)
461 {
462 BulletShape newShape = new BulletShape(IntPtr.Zero);
463
464 float lod;
465 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
466
467 // if this new shape is the same as last time, don't recreate the mesh
468 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
469 return false;
470
471 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
472 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
473
474 // Since we're recreating new, get rid of the reference to the previous shape
475 DereferenceShape(prim.BSShape, true, shapeCallback);
476
477 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
478
479 ReferenceShape(newShape);
480
481 // meshes are already scaled by the meshmerizer
482 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
483 prim.BSShape = newShape;
484
485 return true; // 'true' means a new shape has been added to this prim
486 }
487
488 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
489 {
490 IMesh meshData = null;
491 IntPtr meshPtr;
492 MeshDesc meshDesc;
493 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
494 {
495 // If the mesh has already been built just use it.
496 meshPtr = meshDesc.ptr;
497 }
498 else
499 {
500 // Pass false for physicalness as this creates some sort of bounding box which we don't need
501 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
502
503 int[] indices = meshData.getIndexListAsInt();
504 List<OMV.Vector3> vertices = meshData.getVertexList();
505
506 float[] verticesAsFloats = new float[vertices.Count * 3];
507 int vi = 0;
508 foreach (OMV.Vector3 vv in vertices)
509 {
510 verticesAsFloats[vi++] = vv.X;
511 verticesAsFloats[vi++] = vv.Y;
512 verticesAsFloats[vi++] = vv.Z;
513 }
514
515 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
516 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
517
518 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
519 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
520 }
521 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
522 newShape.shapeKey = newMeshKey;
523
524 return newShape;
525 }
526
527 // See that hull shape exists in the physical world and update prim.BSShape.
528 // We could be creating the hull because scale changed or whatever.
529 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
530 ShapeDestructionCallback shapeCallback)
531 {
532 BulletShape newShape;
533
534 float lod;
535 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
536
537 // if the hull hasn't changed, don't rebuild it
538 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
539 return false;
540
541 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
542 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
543
544 // Remove usage of the previous shape.
545 DereferenceShape(prim.BSShape, true, shapeCallback);
546
547 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
548
549 ReferenceShape(newShape);
550
551 // hulls are already scaled by the meshmerizer
552 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
553 prim.BSShape = newShape;
554 return true; // 'true' means a new shape has been added to this prim
555 }
556
557 List<ConvexResult> m_hulls;
558 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
559 {
560
561 IntPtr hullPtr;
562 HullDesc hullDesc;
563 if (Hulls.TryGetValue(newHullKey, out hullDesc))
564 {
565 // If the hull shape already is created, just use it.
566 hullPtr = hullDesc.ptr;
567 }
568 else
569 {
570 // Build a new hull in the physical world
571 // Pass false for physicalness as this creates some sort of bounding box which we don't need
572 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
573
574 int[] indices = meshData.getIndexListAsInt();
575 List<OMV.Vector3> vertices = meshData.getVertexList();
576
577 //format conversion from IMesh format to DecompDesc format
578 List<int> convIndices = new List<int>();
579 List<float3> convVertices = new List<float3>();
580 for (int ii = 0; ii < indices.GetLength(0); ii++)
581 {
582 convIndices.Add(indices[ii]);
583 }
584 foreach (OMV.Vector3 vv in vertices)
585 {
586 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
587 }
588
589 // setup and do convex hull conversion
590 m_hulls = new List<ConvexResult>();
591 DecompDesc dcomp = new DecompDesc();
592 dcomp.mIndices = convIndices;
593 dcomp.mVertices = convVertices;
594 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
595 // create the hull into the _hulls variable
596 convexBuilder.process(dcomp);
597
598 // Convert the vertices and indices for passing to unmanaged.
599 // The hull information is passed as a large floating point array.
600 // The format is:
601 // convHulls[0] = number of hulls
602 // convHulls[1] = number of vertices in first hull
603 // convHulls[2] = hull centroid X coordinate
604 // convHulls[3] = hull centroid Y coordinate
605 // convHulls[4] = hull centroid Z coordinate
606 // convHulls[5] = first hull vertex X
607 // convHulls[6] = first hull vertex Y
608 // convHulls[7] = first hull vertex Z
609 // convHulls[8] = second hull vertex X
610 // ...
611 // convHulls[n] = number of vertices in second hull
612 // convHulls[n+1] = second hull centroid X coordinate
613 // ...
614 //
615 // TODO: is is very inefficient. Someday change the convex hull generator to return
616 // data structures that do not need to be converted in order to pass to Bullet.
617 // And maybe put the values directly into pinned memory rather than marshaling.
618 int hullCount = m_hulls.Count;
619 int totalVertices = 1; // include one for the count of the hulls
620 foreach (ConvexResult cr in m_hulls)
621 {
622 totalVertices += 4; // add four for the vertex count and centroid
623 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
624 }
625 float[] convHulls = new float[totalVertices];
626
627 convHulls[0] = (float)hullCount;
628 int jj = 1;
629 foreach (ConvexResult cr in m_hulls)
630 {
631 // copy vertices for index access
632 float3[] verts = new float3[cr.HullVertices.Count];
633 int kk = 0;
634 foreach (float3 ff in cr.HullVertices)
635 {
636 verts[kk++] = ff;
637 }
638
639 // add to the array one hull's worth of data
640 convHulls[jj++] = cr.HullIndices.Count;
641 convHulls[jj++] = 0f; // centroid x,y,z
642 convHulls[jj++] = 0f;
643 convHulls[jj++] = 0f;
644 foreach (int ind in cr.HullIndices)
645 {
646 convHulls[jj++] = verts[ind].x;
647 convHulls[jj++] = verts[ind].y;
648 convHulls[jj++] = verts[ind].z;
649 }
650 }
651 // create the hull data structure in Bullet
652 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
653 }
654
655 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
656 newShape.shapeKey = newHullKey;
657
658 return newShape; // 'true' means a new shape has been added to this prim
659 }
660
661 // Callback from convex hull creater with a newly created hull.
662 // Just add it to our collection of hulls for this shape.
663 private void HullReturn(ConvexResult result)
664 {
665 m_hulls.Add(result);
666 return;
667 }
668
669 // Create a hash of all the shape parameters to be used as a key
670 // for this particular shape.
671 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
672 {
673 // level of detail based on size and type of the object
674 float lod = PhysicsScene.MeshLOD;
675 if (pbs.SculptEntry)
676 lod = PhysicsScene.SculptLOD;
677
678 // Mega prims usually get more detail because one can interact with shape approximations at this size.
679 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
680 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
681 lod = PhysicsScene.MeshMegaPrimLOD;
682
683 retLod = lod;
684 return pbs.GetMeshKey(shapeData.Size, lod);
685 }
686 // For those who don't want the LOD
687 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
688 {
689 float lod;
690 return ComputeShapeKey(shapeData, pbs, out lod);
691 }
692
693 // Create a body object in Bullet.
694 // Updates prim.BSBody with the information about the new body if one is created.
695 // Returns 'true' if an object was actually created.
696 // Called at taint-time.
697 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
698 ShapeData shapeData, BodyDestructionCallback bodyCallback)
699 {
700 bool ret = false;
701
702 // the mesh, hull or native shape must have already been created in Bullet
703 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
704
705 // If there is an existing body, verify it's of an acceptable type.
706 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
707 if (!mustRebuild)
708 {
709 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
710 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
711 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
712 {
713 // If the collisionObject is not the correct type for solidness, rebuild what's there
714 mustRebuild = true;
715 }
716
717 }
718
719 if (mustRebuild || forceRebuild)
720 {
721 // Free any old body
722 DereferenceBody(prim.BSBody, true, bodyCallback);
723
724 BulletBody aBody;
725 IntPtr bodyPtr = IntPtr.Zero;
726 if (prim.IsSolid)
727 {
728 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
729 shapeData.ID, shapeData.Position, shapeData.Rotation);
730 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
731 }
732 else
733 {
734 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
735 shapeData.ID, shapeData.Position, shapeData.Rotation);
736 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
737 }
738 aBody = new BulletBody(shapeData.ID, bodyPtr);
739
740 ReferenceBody(aBody, true);
741
742 prim.BSBody = aBody;
743
744 ret = true;
745 }
746
747 return ret;
748 }
749
750 private void DetailLog(string msg, params Object[] args)
751 {
752 if (PhysicsScene.PhysicsLogging.Enabled)
753 PhysicsScene.DetailLog(msg, args);
754 }
755}
756}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..caf411e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,492 @@
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 copyrightD
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public class BSTerrainManager
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46
47 // These height values are fractional so the odd values will be
48 // noticable when debugging.
49 public const float HEIGHT_INITIALIZATION = 24.987f;
50 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
51 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
52
53 // If the min and max height are equal, we reduce the min by this
54 // amount to make sure that a bounding box is built for the terrain.
55 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
56
57 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
58
59 // Until the whole simulator is changed to pass us the region size, we rely on constants.
60 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
61
62 // The scene that I am part of
63 private BSScene PhysicsScene { get; set; }
64
65 // The ground plane created to keep thing from falling to infinity.
66 private BulletBody m_groundPlane;
67
68 // If doing mega-regions, if we're region zero we will be managing multiple
69 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
71
72 // True of the terrain has been modified.
73 // Used to force recalculation of terrain height after terrain has been modified
74 private bool m_terrainModified;
75
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
77 // This is incremented before assigning to new region so it is the last ID allocated.
78 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
79 public uint HighestTerrainID { get {return m_terrainCount; } }
80
81 // If doing mega-regions, this holds our offset from region zero of
82 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
83 private Vector3 m_worldOffset;
84 // If the parent region (region 0), this is the extent of the combined regions
85 // relative to the origin of region zero
86 private Vector3 m_worldMax;
87 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
88
89 public BSTerrainManager(BSScene physicsScene)
90 {
91 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
93 m_terrainModified = false;
94
95 // Assume one region of default size
96 m_worldOffset = Vector3.Zero;
97 m_worldMax = new Vector3(DefaultRegionSize);
98 MegaRegionParentPhysicsScene = null;
99 }
100
101 // Create the initial instance of terrain and the underlying ground plane.
102 // The objects are allocated in the unmanaged space and the pointers are tracked
103 // by the managed code.
104 // The terrains and the groundPlane are not added to the list of PhysObjects.
105 // This is called from the initialization routine so we presume it is
106 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain()
108 {
109 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape(
111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 // Ground plane does not move
118 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
119 // Everything collides with the ground plane.
120 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
121 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
122
123 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
124 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
125 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
126 float[] initialMap = new float[totalHeights];
127 for (int ii = 0; ii < totalHeights; ii++)
128 {
129 initialMap[ii] = HEIGHT_INITIALIZATION;
130 }
131 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
132 }
133
134 // Release all the terrain structures we might have allocated
135 public void ReleaseGroundPlaneAndTerrain()
136 {
137 if (m_groundPlane.ptr != IntPtr.Zero)
138 {
139 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
140 {
141 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
142 }
143 m_groundPlane.ptr = IntPtr.Zero;
144 }
145
146 ReleaseTerrain();
147 }
148
149 // Release all the terrain we have allocated
150 public void ReleaseTerrain()
151 {
152 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
153 {
154 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
155 {
156 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
157 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
158 }
159 }
160 m_heightMaps.Clear();
161 }
162
163 // The simulator wants to set a new heightmap for the terrain.
164 public void SetTerrain(float[] heightMap) {
165 float[] localHeightMap = heightMap;
166 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
167 {
168 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
169 {
170 // If a child of a mega-region, we shouldn't have any terrain allocated for us
171 ReleaseGroundPlaneAndTerrain();
172 // If doing the mega-prim stuff and we are the child of the zero region,
173 // the terrain is added to our parent
174 if (MegaRegionParentPhysicsScene is BSScene)
175 {
176 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
177 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
178 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
179 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
180 }
181 }
182 else
183 {
184 // If not doing the mega-prim thing, just change the terrain
185 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
186
187 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
188 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
189 }
190 });
191 }
192
193 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
194 // based on the passed information. The 'id' should be either the terrain id or
195 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
196 // The latter feature is for creating child terrains for mega-regions.
197 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
198 // then a new body and shape is created and the mapInfo is filled.
199 // This call is used for doing the initial terrain creation.
200 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
201 // terrain shape is created and added to the body.
202 // This call is most often used to update the heightMap and parameters of the terrain.
203 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
204 // calling this routine from initialization or taint-time routines) or whether to delay
205 // all the unmanaged activities to taint-time.
206 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
207 {
208 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
209 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
210
211 float minZ = float.MaxValue;
212 float maxZ = float.MinValue;
213 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
214
215 int heightMapSize = heightMap.Length;
216 for (int ii = 0; ii < heightMapSize; ii++)
217 {
218 float height = heightMap[ii];
219 if (height < minZ) minZ = height;
220 if (height > maxZ) maxZ = height;
221 }
222
223 // The shape of the terrain is from its base to its extents.
224 minCoords.Z = minZ;
225 maxCoords.Z = maxZ;
226
227 BulletHeightMapInfo mapInfo;
228 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
229 {
230 // If this is terrain we know about, it's easy to update
231
232 mapInfo.heightMap = heightMap;
233 mapInfo.minCoords = minCoords;
234 mapInfo.maxCoords = maxCoords;
235 mapInfo.minZ = minZ;
236 mapInfo.maxZ = maxZ;
237 mapInfo.sizeX = maxCoords.X - minCoords.X;
238 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
239 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
240 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
241
242 BSScene.TaintCallback rebuildOperation = delegate()
243 {
244 if (MegaRegionParentPhysicsScene != null)
245 {
246 // It's possible that Combine() was called after this code was queued.
247 // If we are a child of combined regions, we don't create any terrain for us.
248 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
249
250 // Get rid of any terrain that may have been allocated for us.
251 ReleaseGroundPlaneAndTerrain();
252
253 // I hate doing this, but just bail
254 return;
255 }
256
257 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
258 {
259 // Updating an existing terrain.
260 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
261 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
262
263 // Remove from the dynamics world because we're going to mangle this object
264 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
265
266 // Get rid of the old terrain
267 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
268 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
269 mapInfo.Ptr = IntPtr.Zero;
270
271 /*
272 // NOTE: This routine is half here because I can't get the terrain shape replacement
273 // to work. In the short term, the above three lines completely delete the old
274 // terrain and the code below recreates one from scratch.
275 // Hopefully the Bullet community will help me out on this one.
276
277 // First, release the old collision shape (there is only one terrain)
278 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
279
280 // Fill the existing height map info with the new location and size information
281 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
282 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
283
284 // Create a terrain shape based on the new info
285 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
286
287 // Stuff the shape into the existing terrain body
288 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
289 */
290 }
291 // else
292 {
293 // Creating a new terrain.
294 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
295 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
296
297 mapInfo.ID = id;
298 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
299 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
300
301 // Create the terrain shape from the mapInfo
302 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
303 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
304
305 // The terrain object initial position is at the center of the object
306 Vector3 centerPos;
307 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
308 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
309 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
310
311 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
312 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
313 id, centerPos, Quaternion.Identity));
314 }
315
316 // Make sure the entry is in the heightmap table
317 m_heightMaps[terrainRegionBase] = mapInfo;
318
319 // Set current terrain attributes
320 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
321 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
322 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
323 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
324
325 // Return the new terrain to the world of physical objects
326 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
327
328 // redo its bounding box now that it is in the world
329 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
330
331 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
332 (uint)CollisionFilterGroups.TerrainFilter,
333 (uint)CollisionFilterGroups.TerrainMask);
334
335 // Make sure the new shape is processed.
336 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338
339 m_terrainModified = true;
340 };
341
342 // There is the option to do the changes now (we're already in 'taint time'), or
343 // to do the Bullet operations later.
344 if (inTaintTime)
345 rebuildOperation();
346 else
347 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
348 }
349 else
350 {
351 // We don't know about this terrain so either we are creating a new terrain or
352 // our mega-prim child is giving us a new terrain to add to the phys world
353
354 // if this is a child terrain, calculate a unique terrain id
355 uint newTerrainID = id;
356 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
357 newTerrainID = ++m_terrainCount;
358
359 float[] heightMapX = heightMap;
360 Vector3 minCoordsX = minCoords;
361 Vector3 maxCoordsX = maxCoords;
362
363 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
364 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
365
366 // Code that must happen at taint-time
367 BSScene.TaintCallback createOperation = delegate()
368 {
369 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
370 // Create a new mapInfo that will be filled with the new info
371 mapInfo = new BulletHeightMapInfo(id, heightMapX,
372 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
373 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
374 // Put the unfilled heightmap info into the collection of same
375 m_heightMaps.Add(terrainRegionBase, mapInfo);
376 // Build the terrain
377 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
378
379 m_terrainModified = true;
380 };
381
382 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
383 if (inTaintTime)
384 createOperation();
385 else
386 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
387 }
388 }
389
390 // Someday we will have complex terrain with caves and tunnels
391 public float GetTerrainHeightAtXYZ(Vector3 loc)
392 {
393 // For the moment, it's flat and convex
394 return GetTerrainHeightAtXY(loc.X, loc.Y);
395 }
396
397 // Given an X and Y, find the height of the terrain.
398 // Since we could be handling multiple terrains for a mega-region,
399 // the base of the region is calcuated assuming all regions are
400 // the same size and that is the default.
401 // Once the heightMapInfo is found, we have all the information to
402 // compute the offset into the array.
403 private float lastHeightTX = 999999f;
404 private float lastHeightTY = 999999f;
405 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
406 private float GetTerrainHeightAtXY(float tX, float tY)
407 {
408 // You'd be surprized at the number of times this routine is called
409 // with the same parameters as last time.
410 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
411 return lastHeight;
412
413 lastHeightTX = tX;
414 lastHeightTY = tY;
415 float ret = HEIGHT_GETHEIGHT_RET;
416
417 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
418 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
419 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
420
421 BulletHeightMapInfo mapInfo;
422 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
423 {
424 float regionX = tX - offsetX;
425 float regionY = tY - offsetY;
426 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
427 try
428 {
429 ret = mapInfo.heightMap[mapIndex];
430 }
431 catch
432 {
433 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
434 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
435 LogHeader, terrainBaseXY, regionX, regionY);
436 ret = HEIGHT_GETHEIGHT_RET;
437 }
438 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
439 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
440 }
441 else
442 {
443 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
444 LogHeader, PhysicsScene.RegionName, tX, tY);
445 }
446 m_terrainModified = false;
447 lastHeight = ret;
448 return ret;
449 }
450
451 // Although no one seems to check this, I do support combining.
452 public bool SupportsCombining()
453 {
454 return true;
455 }
456
457 // This routine is called two ways:
458 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
459 // extent of the combined regions. This is to inform the parent of the size
460 // of the combined regions.
461 // and one with 'offset' as the offset of the child region to the base region,
462 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
463 // child of its relative base and new parent.
464 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
465 {
466 m_worldOffset = offset;
467 m_worldMax = extents;
468 MegaRegionParentPhysicsScene = pScene;
469 if (pScene != null)
470 {
471 // We are a child.
472 // We want m_worldMax to be the highest coordinate of our piece of terrain.
473 m_worldMax = offset + DefaultRegionSize;
474 }
475 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
476 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
477 }
478
479 // Unhook all the combining that I know about.
480 public void UnCombine(PhysicsScene pScene)
481 {
482 // Just like ODE, for the moment a NOP
483 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
484 }
485
486
487 private void DetailLog(string msg, params Object[] args)
488 {
489 PhysicsScene.PhysicsLogging.Write(msg, args);
490 }
491}
492}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 504bd3c..276111c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -33,38 +33,153 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API 35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
36public struct BulletSim 39public struct BulletSim
37{ 40{
38 public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } 41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
39 public uint ID; 42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
40 // The scene is only in here so very low level routines have a handle to print debug/error messages 49 // The scene is only in here so very low level routines have a handle to print debug/error messages
41 public BSScene scene; 50 public BSScene physicsScene;
42 public IntPtr Ptr;
43} 51}
44 52
53// An allocated Bullet btRigidBody
45public struct BulletBody 54public struct BulletBody
46{ 55{
47 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } 56 public BulletBody(uint id, IntPtr xx)
48 public IntPtr Ptr; 57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
49 public uint ID; 64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
50} 120}
51 121
122 // Constraint type values as defined by Bullet
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
52public struct BulletConstraint 136public struct BulletConstraint
53{ 137{
54 public BulletConstraint(IntPtr xx) { Ptr = xx; } 138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = new Vector2(0f, 0f);
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
55 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector2 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
56} 171}
57 172
58// =============================================================================== 173// ===============================================================================
59[StructLayout(LayoutKind.Sequential)] 174[StructLayout(LayoutKind.Sequential)]
60public struct ConvexHull 175public struct ConvexHull
61{ 176{
62 Vector3 Offset; 177 Vector3 Offset;
63 int VertexCount; 178 int VertexCount;
64 Vector3[] Vertices; 179 Vector3[] Vertices;
65} 180}
66[StructLayout(LayoutKind.Sequential)] 181[StructLayout(LayoutKind.Sequential)]
67public struct ShapeData 182public struct ShapeData
68{ 183{
69 public enum PhysicsShapeType 184 public enum PhysicsShapeType
70 { 185 {
@@ -75,7 +190,10 @@ public struct ShapeData
75 SHAPE_CYLINDER = 4, 190 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5, 191 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6, 192 SHAPE_MESH = 6,
78 SHAPE_HULL = 7 193 SHAPE_HULL = 7,
194 // following defined by BulletSim
195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
79 }; 197 };
80 public uint ID; 198 public uint ID;
81 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -91,13 +209,24 @@ public struct ShapeData
91 public float Restitution; 209 public float Restitution;
92 public float Collidable; // true of things bump into this 210 public float Collidable; // true of things bump into this
93 public float Static; // true if a static object. Otherwise gravity, etc. 211 public float Static; // true if a static object. Otherwise gravity, etc.
212 public float Solid; // true if object cannot be passed through
213 public Vector3 Size;
94 214
95 // note that bools are passed as floats since bool size changes by language and architecture 215 // note that bools are passed as floats since bool size changes by language and architecture
96 public const float numericTrue = 1f; 216 public const float numericTrue = 1f;
97 public const float numericFalse = 0f; 217 public const float numericFalse = 0f;
218
219 // The native shapes have predefined shape hash keys
220 public enum FixedShapeKey : ulong
221 {
222 KEY_BOX = 1,
223 KEY_SPHERE = 2,
224 KEY_CONE = 3,
225 KEY_CYLINDER = 4,
226 }
98} 227}
99[StructLayout(LayoutKind.Sequential)] 228[StructLayout(LayoutKind.Sequential)]
100public struct SweepHit 229public struct SweepHit
101{ 230{
102 public uint ID; 231 public uint ID;
103 public float Fraction; 232 public float Fraction;
@@ -174,12 +303,38 @@ public struct ConfigurationParameters
174 public float linkConstraintTransMotorMaxForce; 303 public float linkConstraintTransMotorMaxForce;
175 public float linkConstraintERP; 304 public float linkConstraintERP;
176 public float linkConstraintCFM; 305 public float linkConstraintCFM;
306 public float linkConstraintSolverIterations;
307
308 public float physicsLoggingFrames;
177 309
178 public const float numericTrue = 1f; 310 public const float numericTrue = 1f;
179 public const float numericFalse = 0f; 311 public const float numericFalse = 0f;
180} 312}
181 313
182// Values used by Bullet and BulletSim to control collisions 314
315// The states a bullet collision object can have
316public enum ActivationState : uint
317{
318 ACTIVE_TAG = 1,
319 ISLAND_SLEEPING,
320 WANTS_DEACTIVATION,
321 DISABLE_DEACTIVATION,
322 DISABLE_SIMULATION,
323}
324
325public enum CollisionObjectTypes : int
326{
327 CO_COLLISION_OBJECT = 1 << 0,
328 CO_RIGID_BODY = 1 << 1,
329 CO_GHOST_OBJECT = 1 << 2,
330 CO_SOFT_BODY = 1 << 3,
331 CO_HF_FLUID = 1 << 4,
332 CO_USER_TYPE = 1 << 5,
333}
334
335// Values used by Bullet and BulletSim to control object properties.
336// Bullet's "CollisionFlags" has more to do with operations on the
337// object (if collisions happen, if gravity effects it, ...).
183public enum CollisionFlags : uint 338public enum CollisionFlags : uint
184{ 339{
185 CF_STATIC_OBJECT = 1 << 0, 340 CF_STATIC_OBJECT = 1 << 0,
@@ -191,11 +346,55 @@ public enum CollisionFlags : uint
191 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 346 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
192 // Following used by BulletSim to control collisions 347 // Following used by BulletSim to control collisions
193 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 348 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
194 BS_VOLUME_DETECT_OBJECT = 1 << 11, 349 BS_FLOATS_ON_WATER = 1 << 11,
195 BS_PHANTOM_OBJECT = 1 << 12, 350 BS_NONE = 0,
196 BS_PHYSICAL_OBJECT = 1 << 13, 351 BS_ALL = 0xFFFFFFFF,
352
353 // These are the collision flags switched depending on physical state.
354 // The other flags are used for other things and should not be fooled with.
355 BS_ACTIVE = CF_STATIC_OBJECT
356 | CF_KINEMATIC_OBJECT
357 | CF_NO_CONTACT_RESPONSE
358};
359
360// Values for collisions groups and masks
361public enum CollisionFilterGroups : uint
362{
363 // Don't use the bit definitions!! Define the use in a
364 // filter/mask definition below. This way collision interactions
365 // are more easily debugged.
366 BNoneFilter = 0,
367 BDefaultFilter = 1 << 0,
368 BStaticFilter = 1 << 1,
369 BKinematicFilter = 1 << 2,
370 BDebrisFilter = 1 << 3,
371 BSensorTrigger = 1 << 4,
372 BCharacterFilter = 1 << 5,
373 BAllFilter = 0xFFFFFFFF,
374 // Filter groups defined by BulletSim
375 BGroundPlaneFilter = 1 << 10,
376 BTerrainFilter = 1 << 11,
377 BRaycastFilter = 1 << 12,
378 BSolidFilter = 1 << 13,
379
380 // The collsion filters and masked are defined in one place -- don't want them scattered
381 AvatarFilter = BCharacterFilter,
382 AvatarMask = BAllFilter,
383 ObjectFilter = BSolidFilter,
384 ObjectMask = BAllFilter,
385 StaticObjectFilter = BStaticFilter,
386 StaticObjectMask = BAllFilter,
387 VolumeDetectFilter = BSensorTrigger,
388 VolumeDetectMask = ~BSensorTrigger,
389 TerrainFilter = BTerrainFilter,
390 TerrainMask = BAllFilter & ~BStaticFilter,
391 GroundPlaneFilter = BAllFilter,
392 GroundPlaneMask = BAllFilter
393
197}; 394};
198 395
396
397
199// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 398// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
200// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. 399// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
201public enum ConstraintParams : int 400public enum ConstraintParams : int
@@ -221,14 +420,22 @@ public enum ConstraintParamAxis : int
221// =============================================================================== 420// ===============================================================================
222static class BulletSimAPI { 421static class BulletSimAPI {
223 422
423// Link back to the managed code for outputting log messages
424[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
425public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
426
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 427[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
225[return: MarshalAs(UnmanagedType.LPStr)] 428[return: MarshalAs(UnmanagedType.LPStr)]
226public static extern string GetVersion(); 429public static extern string GetVersion();
227 430
228[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 431[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
229public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 432public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
230 int maxCollisions, IntPtr collisionArray, 433 int maxCollisions, IntPtr collisionArray,
231 int maxUpdates, IntPtr updateArray); 434 int maxUpdates, IntPtr updateArray,
435 DebugLogCallback logRoutine);
436
437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
438public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
232 439
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 441public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
@@ -242,19 +449,19 @@ public static extern bool UpdateParameter(uint worldID, uint localID,
242 449
243// =============================================================================== 450// ===============================================================================
244[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
245public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 452public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
246 out int updatedEntityCount, 453 out int updatedEntityCount,
247 out IntPtr updatedEntitiesPtr, 454 out IntPtr updatedEntitiesPtr,
248 out int collidersCount, 455 out int collidersCount,
249 out IntPtr collidersPtr); 456 out IntPtr collidersPtr);
250 457
251[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 458[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
252public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 459public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
253 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls 460 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
254 ); 461 );
255 462
256[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
257public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 464public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
258 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 465 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
259 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices 466 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
260 ); 467 );
@@ -268,23 +475,6 @@ public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
269public static extern bool CreateObject(uint worldID, ShapeData shapeData); 476public static extern bool CreateObject(uint worldID, ShapeData shapeData);
270 477
271/* Remove old functionality
272[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
273public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
274
275[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
276public static extern void AddConstraint(uint worldID, uint id1, uint id2,
277 Vector3 frame1, Quaternion frame1rot,
278 Vector3 frame2, Quaternion frame2rot,
279 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
280
281[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
282public static extern bool RemoveConstraintByID(uint worldID, uint id1);
283
284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
285public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
286 */
287
288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
289public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 479public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
290 480
@@ -300,6 +490,7 @@ public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 veloc
300[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
301public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); 491public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
302 492
493// Set the current force acting on the object
303[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
304public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); 495public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
305 496
@@ -342,8 +533,6 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
342public static extern void DumpBulletStatistics(); 533public static extern void DumpBulletStatistics();
343 534
344// Log a debug message 535// Log a debug message
345[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
346public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
348public static extern void SetDebugLogCallback(DebugLogCallback callback); 537public static extern void SetDebugLogCallback(DebugLogCallback callback);
349 538
@@ -358,6 +547,7 @@ public static extern void SetDebugLogCallback(DebugLogCallback callback);
358// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt 547// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
359// and the old code is removed. 548// and the old code is removed.
360 549
550// Functions use while converting from API1 to API2. Can be removed when totally converted.
361[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
362public static extern IntPtr GetSimHandle2(uint worldID); 552public static extern IntPtr GetSimHandle2(uint worldID);
363 553
@@ -368,6 +558,7 @@ public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
368public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); 558public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
369 559
370// =============================================================================== 560// ===============================================================================
561// Initialization and simulation
371[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 562[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
372public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 563public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
373 int maxCollisions, IntPtr collisionArray, 564 int maxCollisions, IntPtr collisionArray,
@@ -377,14 +568,14 @@ public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
377public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 568public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
378 569
379[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
380public static extern void SetHeightmap2(IntPtr world, float[] heightmap); 571public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
381 572
382[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 573[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
383public static extern void Shutdown2(IntPtr sim); 574public static extern void Shutdown2(IntPtr sim);
384 575
385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
386public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 577public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
387 out int updatedEntityCount, 578 out int updatedEntityCount,
388 out IntPtr updatedEntitiesPtr, 579 out IntPtr updatedEntitiesPtr,
389 out int collidersCount, 580 out int collidersCount,
390 out IntPtr collidersPtr); 581 out IntPtr collidersPtr);
@@ -392,24 +583,87 @@ public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSt
392[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 583[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
393public static extern bool PushUpdate2(IntPtr obj); 584public static extern bool PushUpdate2(IntPtr obj);
394 585
395/* 586// =====================================================================================
587// Mesh, hull, shape and body creation helper routines
588[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
589public static extern IntPtr CreateMeshShape2(IntPtr world,
590 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
591 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
592
593[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
594public static extern IntPtr CreateHullShape2(IntPtr world,
595 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
596
597[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
598public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
599
600[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
601public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
602
603[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
604public static extern bool IsNativeShape2(IntPtr shape);
605
606[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
607public static extern IntPtr CreateCompoundShape2(IntPtr sim);
608
609[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
610public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
611
612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
613public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
614
615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
616public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
617
618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
619public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
620
621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
622public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
623
624[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
625public static extern int GetBodyType2(IntPtr obj);
626
396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 627[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
397public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices ); 628public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
398 629
399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 630[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
400public static extern bool BuildHull2(IntPtr world, IntPtr mesh); 631public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
401 632
402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
403public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh); 634public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
404 635
405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 636[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
406public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh); 637public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
407 638
408[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
409public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData); 640public static extern void ReleaseBodyInfo2(IntPtr obj);
410*/
411 641
412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
643public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
644
645// =====================================================================================
646// Terrain creation and helper routines
647[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
648public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
649 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
650
651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
652public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
653 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
654
655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
656public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
657
658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
659public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
660
661[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
662public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
663
664// =====================================================================================
665// Constraint creation and helper routines
666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
413public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 667public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
414 Vector3 frame1loc, Quaternion frame1rot, 668 Vector3 frame1loc, Quaternion frame1rot,
415 Vector3 frame2loc, Quaternion frame2rot, 669 Vector3 frame2loc, Quaternion frame2rot,
@@ -433,7 +687,7 @@ public static extern void SetConstraintEnable2(IntPtr constrain, float numericTr
433public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 687public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
434 688
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 689[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern bool SetFrames2(IntPtr constrain, 690public static extern bool SetFrames2(IntPtr constrain,
437 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); 691 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
438 692
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -460,11 +714,108 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
461public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 715public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
462 716
717// =====================================================================================
718// btCollisionWorld entries
719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
720public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
721
722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
723public static extern void UpdateAabbs2(IntPtr world);
724
725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
726public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
727
728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
729public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
730
731// =====================================================================================
732// btDynamicsWorld entries
733[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
734public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
735
736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
737public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
738
739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
740public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
741
742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
743public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
744// =====================================================================================
745// btCollisionObject entries
746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
747public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
748
749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
750public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
751
752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
753public static extern bool HasAnisotripicFriction2(IntPtr constrain);
754
755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
756public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
757
758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
759public static extern float GetContactProcessingThreshold2(IntPtr obj);
760
761[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
762public static extern bool IsStaticObject2(IntPtr obj);
763
764[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
765public static extern bool IsKinematicObject2(IntPtr obj);
766
767[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
768public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
769
770[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
771public static extern bool HasContactResponse2(IntPtr obj);
772
773[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
774public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
775
776[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
777public static extern IntPtr GetCollisionShape2(IntPtr obj);
778
779[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
780public static extern int GetActivationState2(IntPtr obj);
781
782[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
783public static extern void SetActivationState2(IntPtr obj, int state);
784
785[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
786public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
787
788[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
789public static extern float GetDeactivationTime2(IntPtr obj);
790
791[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
792public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
793
794[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
795public static extern void Activate2(IntPtr obj, bool forceActivation);
796
797[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
798public static extern bool IsActive2(IntPtr obj);
799
800[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
801public static extern void SetRestitution2(IntPtr obj, float val);
802
803[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
804public static extern float GetRestitution2(IntPtr obj);
805
806[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
807public static extern void SetFriction2(IntPtr obj, float val);
808
463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 809[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
464public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); 810public static extern float GetFriction2(IntPtr obj);
465 811
812 /* Haven't defined the type 'Transform'
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 814public static extern Transform GetWorldTransform2(IntPtr obj);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern void setWorldTransform2(IntPtr obj, Transform trans);
818 */
468 819
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 820[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern Vector3 GetPosition2(IntPtr obj); 821public static extern Vector3 GetPosition2(IntPtr obj);
@@ -473,85 +824,290 @@ public static extern Vector3 GetPosition2(IntPtr obj);
473public static extern Quaternion GetOrientation2(IntPtr obj); 824public static extern Quaternion GetOrientation2(IntPtr obj);
474 825
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); 827public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
477 828
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 829[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); 830public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
480 831
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); 833public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
483 834
835 /*
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 836[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); 837public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
486 838
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 839[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern bool AddObjectForce2(IntPtr obj, Vector3 force); 840public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
841 */
489 842
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 843[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); 844public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
492 845
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 846[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); 847public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
495 848
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 849[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); 850public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
498 851
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 852[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern bool SetDeactivationTime2(IntPtr obj, float val); 853public static extern float GetHitFraction2(IntPtr obj);
501 854
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 855[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); 856public static extern void SetHitFraction2(IntPtr obj, float val);
504 857
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 858[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); 859public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
507 860
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 861[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern bool SetFriction2(IntPtr obj, float val); 862public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
510 863
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern bool SetRestitution2(IntPtr obj, float val); 865public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
513 866
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 867[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); 868public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
516 869
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 870[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); 871public static extern float GetCcdMotionThreshold2(IntPtr obj);
519 872
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 873[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); 874public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
875
876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
877public static extern float GetCcdSweepSphereRadius2(IntPtr obj);
878
879[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
880public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val);
881
882[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
883public static extern IntPtr GetUserPointer2(IntPtr obj);
884
885[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
886public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
887
888// =====================================================================================
889// btRigidBody entries
890[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
891public static extern void ApplyGravity2(IntPtr obj);
892
893[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
894public static extern void SetGravity2(IntPtr obj, Vector3 val);
895
896[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
897public static extern Vector3 GetGravity2(IntPtr obj);
898
899[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
900public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
901
902[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
903public static extern float GetLinearDamping2(IntPtr obj);
904
905[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
906public static extern float GetAngularDamping2(IntPtr obj);
907
908[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
909public static extern float GetLinearSleepingThreshold2(IntPtr obj);
910
911[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
912public static extern float GetAngularSleepingThreshold2(IntPtr obj);
913
914[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
915public static extern void ApplyDamping2(IntPtr obj, float timeStep);
916
917[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
918public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
919
920[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
921public static extern Vector3 GetLinearFactor2(IntPtr obj);
922
923[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
924public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
925
926 /*
927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
928public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
929 */
930
931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
932public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
933
934// Add a force to the object as if its mass is one.
935[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
936public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
937
938// Set the force being applied to the object as if its mass is one.
939[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
940public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
941
942[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
943public static extern Vector3 GetTotalForce2(IntPtr obj);
944
945[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
946public static extern Vector3 GetTotalTorque2(IntPtr obj);
947
948[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
949public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
950
951[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
952public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
953
954[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
955public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
956
957[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
958public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
959
960// Apply force at the given point. Will add torque to the object.
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
963
964// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
965[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
966public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
967
968// Apply impulse to the object's torque. Force is scaled by object's mass.
969[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
970public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
971
972// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
975
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public static extern void ClearForces2(IntPtr obj);
978
979[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
980public static extern void ClearAllForces2(IntPtr obj);
981
982[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
983public static extern void UpdateInertiaTensor2(IntPtr obj);
984
985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
986public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
987
988 /*
989[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
990public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
991 */
992
993[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
994public static extern Vector3 GetLinearVelocity2(IntPtr obj);
995
996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
997public static extern Vector3 GetAngularVelocity2(IntPtr obj);
998
999[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1000public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1001
1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1003public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1004
1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1006public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1007
1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1009public static extern void Translate2(IntPtr obj, Vector3 trans);
1010
1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1012public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1013
1014[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1015public static extern bool WantsSleeping2(IntPtr obj);
1016
1017[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1018public static extern void SetAngularFactor2(IntPtr obj, float factor);
1019
1020[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1021public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1022
1023[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1024public static extern Vector3 GetAngularFactor2(IntPtr obj);
1025
1026[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1027public static extern bool IsInWorld2(IntPtr obj);
1028
1029[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1030public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1031
1032[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1033public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1034
1035[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1036public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1037
1038[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1039public static extern int GetNumConstraintRefs2(IntPtr obj);
1040
1041[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1042public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1043
1044// =====================================================================================
1045// btCollisionShape entries
1046
1047[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1048public static extern float GetAngularMotionDisc2(IntPtr shape);
1049
1050[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1051public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1052
1053[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1054public static extern bool IsPolyhedral2(IntPtr shape);
1055
1056[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1057public static extern bool IsConvex2d2(IntPtr shape);
1058
1059[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1060public static extern bool IsConvex2(IntPtr shape);
1061
1062[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1063public static extern bool IsNonMoving2(IntPtr shape);
1064
1065[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1066public static extern bool IsConcave2(IntPtr shape);
1067
1068[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1069public static extern bool IsCompound2(IntPtr shape);
1070
1071[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1072public static extern bool IsSoftBody2(IntPtr shape);
1073
1074[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1075public static extern bool IsInfinite2(IntPtr shape);
522 1076
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1077[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags); 1078public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
525 1079
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1080[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); 1081public static extern Vector3 GetLocalScaling2(IntPtr shape);
528 1082
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1083[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); 1084public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
531 1085
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1086[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); 1087public static extern int GetShapeType2(IntPtr shape);
534 1088
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1089[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern bool UpdateInertiaTensor2(IntPtr obj); 1090public static extern void SetMargin2(IntPtr shape, float val);
537 1091
538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1092[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
539public static extern bool SetGravity2(IntPtr obj, Vector3 val); 1093public static extern float GetMargin2(IntPtr shape);
540 1094
1095// =====================================================================================
1096// Debugging
541[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1097[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
542public static extern IntPtr ClearForces2(IntPtr obj); 1098public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
543 1099
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1100[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr ClearAllForces2(IntPtr obj); 1101public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
546 1102
547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1103[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
548public static extern bool SetMargin2(IntPtr obj, float val); 1104public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
549 1105
550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1106[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
551public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); 1107public static extern void DumpAllInfo2(IntPtr sim);
552 1108
553[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1109[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
554public static extern bool DestroyObject2(IntPtr world, uint id); 1110public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
555 1111
556[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1112[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
557public static extern void DumpPhysicsStatistics2(IntPtr sim); 1113public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index f3b0630..c736557 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
100 private bool m_hackSentFly = false; 100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0; 101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition; 102 private Vector3 m_taintPosition;
103 103 internal bool m_avatarplanted = false;
104 /// <summary> 104 /// <summary>
105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force 105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
106 /// while calculatios are going on 106 /// while calculatios are going on
@@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin
413 set 413 set
414 { 414 {
415 m_iscollidingObj = value; 415 m_iscollidingObj = value;
416 if (value) 416 if (value && !m_avatarplanted)
417 m_pidControllerActive = false; 417 m_pidControllerActive = false;
418 else 418 else
419 m_pidControllerActive = true; 419 m_pidControllerActive = true;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a41c856..eb02536 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -63,6 +63,9 @@ namespace OpenSim.Region.Physics.OdePlugin
63 63
64 private bool m_isphysical; 64 private bool m_isphysical;
65 65
66 public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } }
67 private int m_expectedCollisionContacts = 0;
68
66 /// <summary> 69 /// <summary>
67 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. 70 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
68 /// </summary> 71 /// </summary>
@@ -150,7 +153,7 @@ namespace OpenSim.Region.Physics.OdePlugin
150 153
151 private PrimitiveBaseShape _pbs; 154 private PrimitiveBaseShape _pbs;
152 private OdeScene _parent_scene; 155 private OdeScene _parent_scene;
153 156
154 /// <summary> 157 /// <summary>
155 /// The physics space which contains prim geometries 158 /// The physics space which contains prim geometries
156 /// </summary> 159 /// </summary>
@@ -840,7 +843,7 @@ namespace OpenSim.Region.Physics.OdePlugin
840 int vertexStride, triStride; 843 int vertexStride, triStride;
841 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap 844 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
842 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage 845 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
843 846 m_expectedCollisionContacts = indexCount;
844 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory 847 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
845 848
846 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at 849 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at
@@ -1377,6 +1380,7 @@ Console.WriteLine("CreateGeom:");
1377 { 1380 {
1378//Console.WriteLine(" CreateGeom 1"); 1381//Console.WriteLine(" CreateGeom 1");
1379 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); 1382 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1383 m_expectedCollisionContacts = 3;
1380 } 1384 }
1381 catch (AccessViolationException) 1385 catch (AccessViolationException)
1382 { 1386 {
@@ -1391,6 +1395,7 @@ Console.WriteLine("CreateGeom:");
1391 { 1395 {
1392//Console.WriteLine(" CreateGeom 2"); 1396//Console.WriteLine(" CreateGeom 2");
1393 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1397 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1398 m_expectedCollisionContacts = 4;
1394 } 1399 }
1395 catch (AccessViolationException) 1400 catch (AccessViolationException)
1396 { 1401 {
@@ -1406,6 +1411,7 @@ Console.WriteLine("CreateGeom:");
1406 { 1411 {
1407//Console.WriteLine(" CreateGeom 3"); 1412//Console.WriteLine(" CreateGeom 3");
1408 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1413 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1414 m_expectedCollisionContacts = 4;
1409 } 1415 }
1410 catch (AccessViolationException) 1416 catch (AccessViolationException)
1411 { 1417 {
@@ -1421,6 +1427,7 @@ Console.WriteLine("CreateGeom:");
1421 { 1427 {
1422//Console.WriteLine(" CreateGeom 4"); 1428//Console.WriteLine(" CreateGeom 4");
1423 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); 1429 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1430 m_expectedCollisionContacts = 4;
1424 } 1431 }
1425 catch (AccessViolationException) 1432 catch (AccessViolationException)
1426 { 1433 {
@@ -1446,11 +1453,13 @@ Console.WriteLine("CreateGeom:");
1446 _parent_scene.geom_name_map.Remove(prim_geom); 1453 _parent_scene.geom_name_map.Remove(prim_geom);
1447 _parent_scene.actor_name_map.Remove(prim_geom); 1454 _parent_scene.actor_name_map.Remove(prim_geom);
1448 d.GeomDestroy(prim_geom); 1455 d.GeomDestroy(prim_geom);
1456 m_expectedCollisionContacts = 0;
1449 prim_geom = IntPtr.Zero; 1457 prim_geom = IntPtr.Zero;
1450 } 1458 }
1451 catch (System.AccessViolationException) 1459 catch (System.AccessViolationException)
1452 { 1460 {
1453 prim_geom = IntPtr.Zero; 1461 prim_geom = IntPtr.Zero;
1462 m_expectedCollisionContacts = 0;
1454 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); 1463 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1455 1464
1456 return false; 1465 return false;
@@ -2395,15 +2404,15 @@ Console.WriteLine(" JointCreateFixed");
2395 { 2404 {
2396 get 2405 get
2397 { 2406 {
2398 // Averate previous velocity with the new one so 2407 // Average previous velocity with the new one so
2399 // client object interpolation works a 'little' better 2408 // client object interpolation works a 'little' better
2400 if (_zeroFlag) 2409 if (_zeroFlag)
2401 return Vector3.Zero; 2410 return Vector3.Zero;
2402 2411
2403 Vector3 returnVelocity = Vector3.Zero; 2412 Vector3 returnVelocity = Vector3.Zero;
2404 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2; 2413 returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
2405 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2; 2414 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
2406 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2; 2415 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
2407 return returnVelocity; 2416 return returnVelocity;
2408 } 2417 }
2409 set 2418 set
@@ -2600,6 +2609,7 @@ Console.WriteLine(" JointCreateFixed");
2600 { 2609 {
2601 Vector3 pv = Vector3.Zero; 2610 Vector3 pv = Vector3.Zero;
2602 bool lastZeroFlag = _zeroFlag; 2611 bool lastZeroFlag = _zeroFlag;
2612 float m_minvelocity = 0;
2603 if (Body != (IntPtr)0) // FIXME -> or if it is a joint 2613 if (Body != (IntPtr)0) // FIXME -> or if it is a joint
2604 { 2614 {
2605 d.Vector3 vec = d.BodyGetPosition(Body); 2615 d.Vector3 vec = d.BodyGetPosition(Body);
@@ -2752,8 +2762,21 @@ Console.WriteLine(" JointCreateFixed");
2752 _acceleration = ((_velocity - m_lastVelocity) / 0.1f); 2762 _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
2753 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); 2763 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
2754 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); 2764 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
2765
2766 // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
2767 // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
2768 // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles
2769 // adding these logical exclusion situations to maintain this where I think it was intended to be.
2770 if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
2771 {
2772 m_minvelocity = 0.5f;
2773 }
2774 else
2775 {
2776 m_minvelocity = 0.02f;
2777 }
2755 2778
2756 if (_velocity.ApproxEquals(pv, 0.5f)) 2779 if (_velocity.ApproxEquals(pv, m_minvelocity))
2757 { 2780 {
2758 m_rotationalVelocity = pv; 2781 m_rotationalVelocity = pv;
2759 } 2782 }
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 929b019..cbe21e2 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -336,6 +336,7 @@ namespace OpenSim.Region.Physics.OdePlugin
336 336
337 public int geomContactPointsStartthrottle = 3; 337 public int geomContactPointsStartthrottle = 3;
338 public int geomUpdatesPerThrottledUpdate = 15; 338 public int geomUpdatesPerThrottledUpdate = 15;
339 private const int avatarExpectedContacts = 3;
339 340
340 public float bodyPIDD = 35f; 341 public float bodyPIDD = 35f;
341 public float bodyPIDG = 25; 342 public float bodyPIDG = 25;
@@ -474,6 +475,8 @@ namespace OpenSim.Region.Physics.OdePlugin
474 private OdePrim cp1; 475 private OdePrim cp1;
475 private OdeCharacter cc2; 476 private OdeCharacter cc2;
476 private OdePrim cp2; 477 private OdePrim cp2;
478 private int p1ExpectedPoints = 0;
479 private int p2ExpectedPoints = 0;
477 //private int cStartStop = 0; 480 //private int cStartStop = 0;
478 //private string cDictKey = ""; 481 //private string cDictKey = "";
479 482
@@ -498,6 +501,9 @@ namespace OpenSim.Region.Physics.OdePlugin
498 public int physics_logging_interval = 0; 501 public int physics_logging_interval = 0;
499 public bool physics_logging_append_existing_logfile = false; 502 public bool physics_logging_append_existing_logfile = false;
500 503
504 private bool avplanted = false;
505 private bool av_av_collisions_off = false;
506
501 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); 507 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
502 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); 508 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
503 509
@@ -640,11 +646,14 @@ namespace OpenSim.Region.Physics.OdePlugin
640 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); 646 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
641 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); 647 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
642 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); 648 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
649 avplanted = physicsconfig.GetBoolean("av_planted", false);
650 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
651
643 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); 652 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
644 653
645 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 654 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
646 655
647 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); 656 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
648 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); 657 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
649 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); 658 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
650 659
@@ -659,6 +668,8 @@ namespace OpenSim.Region.Physics.OdePlugin
659 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); 668 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
660 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); 669 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
661 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); 670 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
671
672
662 673
663 if (Environment.OSVersion.Platform == PlatformID.Unix) 674 if (Environment.OSVersion.Platform == PlatformID.Unix)
664 { 675 {
@@ -1064,7 +1075,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1064 1075
1065 PhysicsActor p1; 1076 PhysicsActor p1;
1066 PhysicsActor p2; 1077 PhysicsActor p2;
1067 1078
1079 p1ExpectedPoints = 0;
1080 p2ExpectedPoints = 0;
1081
1068 if (!actor_name_map.TryGetValue(g1, out p1)) 1082 if (!actor_name_map.TryGetValue(g1, out p1))
1069 { 1083 {
1070 p1 = PANull; 1084 p1 = PANull;
@@ -1121,9 +1135,13 @@ namespace OpenSim.Region.Physics.OdePlugin
1121 switch (p1.PhysicsActorType) 1135 switch (p1.PhysicsActorType)
1122 { 1136 {
1123 case (int)ActorTypes.Agent: 1137 case (int)ActorTypes.Agent:
1138 p1ExpectedPoints = avatarExpectedContacts;
1124 p2.CollidingObj = true; 1139 p2.CollidingObj = true;
1125 break; 1140 break;
1126 case (int)ActorTypes.Prim: 1141 case (int)ActorTypes.Prim:
1142 if (p1 != null && p1 is OdePrim)
1143 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1144
1127 if (p2.Velocity.LengthSquared() > 0.0f) 1145 if (p2.Velocity.LengthSquared() > 0.0f)
1128 p2.CollidingObj = true; 1146 p2.CollidingObj = true;
1129 break; 1147 break;
@@ -1298,6 +1316,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1298 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) 1316 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1299 skipThisContact = true; // No collision on volume detect prims 1317 skipThisContact = true; // No collision on volume detect prims
1300 1318
1319 if (av_av_collisions_off)
1320 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1321 skipThisContact = true;
1322
1301 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) 1323 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1302 skipThisContact = true; // No collision on volume detect prims 1324 skipThisContact = true; // No collision on volume detect prims
1303 1325
@@ -1319,6 +1341,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1319 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && 1341 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1320 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 1342 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1321 { 1343 {
1344 p2ExpectedPoints = avatarExpectedContacts;
1322 // Avatar is moving on terrain, use the movement terrain contact 1345 // Avatar is moving on terrain, use the movement terrain contact
1323 AvatarMovementTerrainContact.geom = curContact; 1346 AvatarMovementTerrainContact.geom = curContact;
1324 1347
@@ -1332,6 +1355,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1332 { 1355 {
1333 if (p2.PhysicsActorType == (int)ActorTypes.Agent) 1356 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1334 { 1357 {
1358 p2ExpectedPoints = avatarExpectedContacts;
1335 // Avatar is standing on terrain, use the non moving terrain contact 1359 // Avatar is standing on terrain, use the non moving terrain contact
1336 TerrainContact.geom = curContact; 1360 TerrainContact.geom = curContact;
1337 1361
@@ -1356,9 +1380,18 @@ namespace OpenSim.Region.Physics.OdePlugin
1356 } 1380 }
1357 1381
1358 if (p2 is OdePrim) 1382 if (p2 is OdePrim)
1359 material = ((OdePrim)p2).m_material; 1383 {
1360 1384 material = ((OdePrim) p2).m_material;
1385 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1386 }
1387
1388 // Unnessesary because p1 is defined above
1389 //if (p1 is OdePrim)
1390 // {
1391 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1392 // }
1361 //m_log.DebugFormat("Material: {0}", material); 1393 //m_log.DebugFormat("Material: {0}", material);
1394
1362 m_materialContacts[material, movintYN].geom = curContact; 1395 m_materialContacts[material, movintYN].geom = curContact;
1363 1396
1364 if (m_global_contactcount < maxContactsbeforedeath) 1397 if (m_global_contactcount < maxContactsbeforedeath)
@@ -1379,7 +1412,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1379 int material = (int)Material.Wood; 1412 int material = (int)Material.Wood;
1380 1413
1381 if (p2 is OdePrim) 1414 if (p2 is OdePrim)
1415 {
1382 material = ((OdePrim)p2).m_material; 1416 material = ((OdePrim)p2).m_material;
1417 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1418 }
1383 1419
1384 //m_log.DebugFormat("Material: {0}", material); 1420 //m_log.DebugFormat("Material: {0}", material);
1385 m_materialContacts[material, movintYN].geom = curContact; 1421 m_materialContacts[material, movintYN].geom = curContact;
@@ -1429,6 +1465,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1429 { 1465 {
1430 if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) 1466 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1431 { 1467 {
1468 p2ExpectedPoints = avatarExpectedContacts;
1432 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) 1469 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1433 { 1470 {
1434 // Avatar is moving on a prim, use the Movement prim contact 1471 // Avatar is moving on a prim, use the Movement prim contact
@@ -1458,7 +1495,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1458 int material = (int)Material.Wood; 1495 int material = (int)Material.Wood;
1459 1496
1460 if (p2 is OdePrim) 1497 if (p2 is OdePrim)
1498 {
1461 material = ((OdePrim)p2).m_material; 1499 material = ((OdePrim)p2).m_material;
1500 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1501 }
1462 1502
1463 //m_log.DebugFormat("Material: {0}", material); 1503 //m_log.DebugFormat("Material: {0}", material);
1464 m_materialContacts[material, 0].geom = curContact; 1504 m_materialContacts[material, 0].geom = curContact;
@@ -1479,8 +1519,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1479 } 1519 }
1480 1520
1481 collision_accounting_events(p1, p2, maxDepthContact); 1521 collision_accounting_events(p1, p2, maxDepthContact);
1482 1522
1483 if (count > geomContactPointsStartthrottle) 1523 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1484 { 1524 {
1485 // If there are more then 3 contact points, it's likely 1525 // If there are more then 3 contact points, it's likely
1486 // that we've got a pile of objects, so ... 1526 // that we've got a pile of objects, so ...
@@ -1943,7 +1983,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1943 1983
1944 newAv.Flying = isFlying; 1984 newAv.Flying = isFlying;
1945 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; 1985 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1946 1986 newAv.m_avatarplanted = avplanted;
1987
1947 return newAv; 1988 return newAv;
1948 } 1989 }
1949 1990
@@ -1958,6 +1999,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1958 1999
1959 internal void AddCharacter(OdeCharacter chr) 2000 internal void AddCharacter(OdeCharacter chr)
1960 { 2001 {
2002 chr.m_avatarplanted = avplanted;
1961 if (!_characters.Contains(chr)) 2003 if (!_characters.Contains(chr))
1962 { 2004 {
1963 _characters.Add(chr); 2005 _characters.Add(chr);
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 3144d76..190fca0 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -39,11 +39,8 @@ using OpenSim.Framework.Console;
39using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
40using Mono.Addins; 40using Mono.Addins;
41 41
42[assembly: Addin("RegionCombinerModule", "0.1")]
43[assembly: AddinDependency("OpenSim", "0.5")]
44namespace OpenSim.Region.RegionCombinerModule 42namespace OpenSim.Region.RegionCombinerModule
45{ 43{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
47 public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule 44 public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule
48 { 45 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
diff --git a/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml b/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml
new file mode 100644
index 0000000..13cb8b6
--- /dev/null
+++ b/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml
@@ -0,0 +1,14 @@
1<Addin id="OpenSim.RegionModules.RegionCombinerModule" version="0.3">
2 <Runtime>
3 <Import assembly="OpenSim.Region.RegionCombinerModule.dll"/>
4 </Runtime>
5
6 <Dependencies>
7 <Addin id="OpenSim" version="0.5" />
8 </Dependencies>
9
10 <Extension path = "/OpenSim/RegionModules">
11 <RegionModule id="RegionCombinerModule" type="OpenSim.Region.RegionCombinerModule.RegionCombinerModule" />
12 </Extension>
13
14</Addin>
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 82de06f..17e3de1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -59,6 +59,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
59using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; 59using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
60using PrimType = OpenSim.Region.Framework.Scenes.PrimType; 60using PrimType = OpenSim.Region.Framework.Scenes.PrimType;
61using AssetLandmark = OpenSim.Framework.AssetLandmark; 61using AssetLandmark = OpenSim.Framework.AssetLandmark;
62using RegionFlags = OpenSim.Framework.RegionFlags;
62 63
63using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; 64using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
64using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; 65using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
@@ -341,7 +342,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
341 return GetLinkParts(m_host, linkType); 342 return GetLinkParts(m_host, linkType);
342 } 343 }
343 344
344 private List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType) 345 public static List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType)
345 { 346 {
346 List<SceneObjectPart> ret = new List<SceneObjectPart>(); 347 List<SceneObjectPart> ret = new List<SceneObjectPart>();
347 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) 348 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
@@ -426,14 +427,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
426 return key; 427 return key;
427 } 428 }
428 429
429 // convert a LSL_Rotation to a Quaternion
430 public static Quaternion Rot2Quaternion(LSL_Rotation r)
431 {
432 Quaternion q = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
433 q.Normalize();
434 return q;
435 }
436
437 //These are the implementations of the various ll-functions used by the LSL scripts. 430 //These are the implementations of the various ll-functions used by the LSL scripts.
438 public LSL_Float llSin(double f) 431 public LSL_Float llSin(double f)
439 { 432 {
@@ -1240,9 +1233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1240 public LSL_Float llGround(LSL_Vector offset) 1233 public LSL_Float llGround(LSL_Vector offset)
1241 { 1234 {
1242 m_host.AddScriptLPS(1); 1235 m_host.AddScriptLPS(1);
1243 Vector3 pos = m_host.GetWorldPosition() + new Vector3((float)offset.x, 1236 Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
1244 (float)offset.y,
1245 (float)offset.z);
1246 1237
1247 //Get the slope normal. This gives us the equation of the plane tangent to the slope. 1238 //Get the slope normal. This gives us the equation of the plane tangent to the slope.
1248 LSL_Vector vsn = llGroundNormal(offset); 1239 LSL_Vector vsn = llGroundNormal(offset);
@@ -1492,31 +1483,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1492 if (part == null || part.ParentGroup.IsDeleted) 1483 if (part == null || part.ParentGroup.IsDeleted)
1493 return; 1484 return;
1494 1485
1495 if (scale.x < 0.01) 1486 // First we need to check whether or not we need to clamp the size of a physics-enabled prim
1496 scale.x = 0.01;
1497 if (scale.y < 0.01)
1498 scale.y = 0.01;
1499 if (scale.z < 0.01)
1500 scale.z = 0.01;
1501
1502 PhysicsActor pa = part.ParentGroup.RootPart.PhysActor; 1487 PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
1503
1504 if (pa != null && pa.IsPhysical) 1488 if (pa != null && pa.IsPhysical)
1505 { 1489 {
1506 if (scale.x > World.m_maxPhys) 1490 scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
1507 scale.x = World.m_maxPhys; 1491 scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
1508 if (scale.y > World.m_maxPhys) 1492 scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
1509 scale.y = World.m_maxPhys; 1493 }
1510 if (scale.z > World.m_maxPhys) 1494 else
1511 scale.z = World.m_maxPhys; 1495 {
1496 // If not physical, then we clamp the scale to the non-physical min/max
1497 scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
1498 scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
1499 scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
1512 } 1500 }
1513
1514 if (scale.x > World.m_maxNonphys)
1515 scale.x = World.m_maxNonphys;
1516 if (scale.y > World.m_maxNonphys)
1517 scale.y = World.m_maxNonphys;
1518 if (scale.z > World.m_maxNonphys)
1519 scale.z = World.m_maxNonphys;
1520 1501
1521 Vector3 tmp = part.Scale; 1502 Vector3 tmp = part.Scale;
1522 tmp.X = (float)scale.x; 1503 tmp.X = (float)scale.x;
@@ -1590,7 +1571,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1590 if (face == ScriptBaseClass.ALL_SIDES) 1571 if (face == ScriptBaseClass.ALL_SIDES)
1591 face = SceneObjectPart.ALL_SIDES; 1572 face = SceneObjectPart.ALL_SIDES;
1592 1573
1593 m_host.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 1574 m_host.SetFaceColorAlpha(face, color, null);
1594 } 1575 }
1595 1576
1596 public void SetTexGen(SceneObjectPart part, int face,int style) 1577 public void SetTexGen(SceneObjectPart part, int face,int style)
@@ -2202,7 +2183,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2202 pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region. 2183 pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
2203 pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region. 2184 pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
2204 pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region. 2185 pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
2205 pos.z > 4096 // return FALSE if altitude than 4096m 2186 pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
2206 ) 2187 )
2207 ) 2188 )
2208 { 2189 {
@@ -2213,14 +2194,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2213 // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read. 2194 // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read.
2214 2195
2215 Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition; 2196 Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
2216 LandData here = World.GetLandData((float)objectPos.X, (float)objectPos.Y); 2197 LandData here = World.GetLandData(objectPos);
2217 LandData there = World.GetLandData((float)pos.x, (float)pos.y); 2198 LandData there = World.GetLandData(pos);
2218 2199
2219 // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits. 2200 // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits.
2220 2201
2221 bool sameParcel = here.GlobalID == there.GlobalID; 2202 bool sameParcel = here.GlobalID == there.GlobalID;
2222 2203
2223 if (!sameParcel && !World.Permissions.CanObjectEntry(m_host.UUID, false, new Vector3((float)pos.x, (float)pos.y, (float)pos.z))) 2204 if (!sameParcel && !World.Permissions.CanRezObject(
2205 m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
2224 { 2206 {
2225 return 0; 2207 return 0;
2226 } 2208 }
@@ -2279,16 +2261,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2279 if (part.ParentGroup.RootPart == part) 2261 if (part.ParentGroup.RootPart == part)
2280 { 2262 {
2281 SceneObjectGroup parent = part.ParentGroup; 2263 SceneObjectGroup parent = part.ParentGroup;
2282 Vector3 dest = new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z); 2264 if (!World.Permissions.CanObjectEntry(parent.UUID, false, (Vector3)toPos))
2283 if (!World.Permissions.CanObjectEntry(parent.UUID, false, dest))
2284 return; 2265 return;
2285 Util.FireAndForget(delegate(object x) { 2266 Util.FireAndForget(delegate(object x) {
2286 parent.UpdateGroupPosition(dest); 2267 parent.UpdateGroupPosition((Vector3)toPos);
2287 }); 2268 });
2288 } 2269 }
2289 else 2270 else
2290 { 2271 {
2291 part.OffsetPosition = new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z); 2272 part.OffsetPosition = (Vector3)toPos;
2292 SceneObjectGroup parent = part.ParentGroup; 2273 SceneObjectGroup parent = part.ParentGroup;
2293 parent.HasGroupChanged = true; 2274 parent.HasGroupChanged = true;
2294 parent.ScheduleGroupForTerseUpdate(); 2275 parent.ScheduleGroupForTerseUpdate();
@@ -2326,7 +2307,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2326 pos = part.AbsolutePosition; 2307 pos = part.AbsolutePosition;
2327 } 2308 }
2328 2309
2329 return new LSL_Vector(pos.X, pos.Y, pos.Z); 2310// m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos);
2311
2312 return new LSL_Vector(pos);
2330 } 2313 }
2331 2314
2332 public void llSetRot(LSL_Rotation rot) 2315 public void llSetRot(LSL_Rotation rot)
@@ -2334,26 +2317,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2334 m_host.AddScriptLPS(1); 2317 m_host.AddScriptLPS(1);
2335 2318
2336 // try to let this work as in SL... 2319 // try to let this work as in SL...
2337 if (m_host.LinkNum < 2) 2320 if (m_host.ParentID == 0)
2338 { 2321 {
2339 // Special case: If we are root, rotate complete SOG to new 2322 // special case: If we are root, rotate complete SOG to new rotation
2340 // rotation. 2323 SetRot(m_host, rot);
2341 // We are root if the link number is 0 (single prim) or 1
2342 // (root prim). ParentID may be nonzero in attachments and
2343 // using it would cause attachments and HUDs to rotate
2344 // to the wrong positions.
2345
2346 SetRot(m_host, Rot2Quaternion(rot));
2347 } 2324 }
2348 else 2325 else
2349 { 2326 {
2350 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. 2327 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
2351 SceneObjectPart rootPart; 2328 SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
2352 if (m_host.ParentGroup != null) // better safe than sorry 2329 if (rootPart != null) // better safe than sorry
2353 { 2330 {
2354 rootPart = m_host.ParentGroup.RootPart; 2331 SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
2355 if (rootPart != null)
2356 SetRot(m_host, rootPart.RotationOffset * Rot2Quaternion(rot));
2357 } 2332 }
2358 } 2333 }
2359 2334
@@ -2363,8 +2338,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2363 public void llSetLocalRot(LSL_Rotation rot) 2338 public void llSetLocalRot(LSL_Rotation rot)
2364 { 2339 {
2365 m_host.AddScriptLPS(1); 2340 m_host.AddScriptLPS(1);
2366 2341 SetRot(m_host, rot);
2367 SetRot(m_host, Rot2Quaternion(rot));
2368 ScriptSleep(200); 2342 ScriptSleep(200);
2369 } 2343 }
2370 2344
@@ -2476,7 +2450,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2476 if (local != 0) 2450 if (local != 0)
2477 force *= llGetRot(); 2451 force *= llGetRot();
2478 2452
2479 m_host.ParentGroup.RootPart.SetForce(new Vector3((float)force.x, (float)force.y, (float)force.z)); 2453 m_host.ParentGroup.RootPart.SetForce(force);
2480 } 2454 }
2481 } 2455 }
2482 2456
@@ -2488,10 +2462,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2488 2462
2489 if (!m_host.ParentGroup.IsDeleted) 2463 if (!m_host.ParentGroup.IsDeleted)
2490 { 2464 {
2491 Vector3 tmpForce = m_host.ParentGroup.RootPart.GetForce(); 2465 force = m_host.ParentGroup.RootPart.GetForce();
2492 force.x = tmpForce.X;
2493 force.y = tmpForce.Y;
2494 force.z = tmpForce.Z;
2495 } 2466 }
2496 2467
2497 return force; 2468 return force;
@@ -2500,8 +2471,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2500 public LSL_Integer llTarget(LSL_Vector position, double range) 2471 public LSL_Integer llTarget(LSL_Vector position, double range)
2501 { 2472 {
2502 m_host.AddScriptLPS(1); 2473 m_host.AddScriptLPS(1);
2503 return m_host.ParentGroup.registerTargetWaypoint( 2474 return m_host.ParentGroup.registerTargetWaypoint(position,
2504 new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range); 2475 (float)range);
2505 } 2476 }
2506 2477
2507 public void llTargetRemove(int number) 2478 public void llTargetRemove(int number)
@@ -2513,8 +2484,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2513 public LSL_Integer llRotTarget(LSL_Rotation rot, double error) 2484 public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
2514 { 2485 {
2515 m_host.AddScriptLPS(1); 2486 m_host.AddScriptLPS(1);
2516 return m_host.ParentGroup.registerRotTargetWaypoint( 2487 return m_host.ParentGroup.registerRotTargetWaypoint(rot, (float)error);
2517 new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), (float)error);
2518 } 2488 }
2519 2489
2520 public void llRotTargetRemove(int number) 2490 public void llRotTargetRemove(int number)
@@ -2526,7 +2496,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2526 public void llMoveToTarget(LSL_Vector target, double tau) 2496 public void llMoveToTarget(LSL_Vector target, double tau)
2527 { 2497 {
2528 m_host.AddScriptLPS(1); 2498 m_host.AddScriptLPS(1);
2529 m_host.MoveToTarget(new Vector3((float)target.x, (float)target.y, (float)target.z), (float)tau); 2499 m_host.MoveToTarget(target, (float)tau);
2530 } 2500 }
2531 2501
2532 public void llStopMoveToTarget() 2502 public void llStopMoveToTarget()
@@ -2539,7 +2509,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2539 { 2509 {
2540 m_host.AddScriptLPS(1); 2510 m_host.AddScriptLPS(1);
2541 //No energy force yet 2511 //No energy force yet
2542 Vector3 v = new Vector3((float)force.x, (float)force.y, (float)force.z); 2512 Vector3 v = force;
2543 if (v.Length() > 20000.0f) 2513 if (v.Length() > 20000.0f)
2544 { 2514 {
2545 v.Normalize(); 2515 v.Normalize();
@@ -2552,13 +2522,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2552 public void llApplyRotationalImpulse(LSL_Vector force, int local) 2522 public void llApplyRotationalImpulse(LSL_Vector force, int local)
2553 { 2523 {
2554 m_host.AddScriptLPS(1); 2524 m_host.AddScriptLPS(1);
2555 m_host.ParentGroup.RootPart.ApplyAngularImpulse(new Vector3((float)force.x, (float)force.y, (float)force.z), local != 0); 2525 m_host.ParentGroup.RootPart.ApplyAngularImpulse(force, local != 0);
2556 } 2526 }
2557 2527
2558 public void llSetTorque(LSL_Vector torque, int local) 2528 public void llSetTorque(LSL_Vector torque, int local)
2559 { 2529 {
2560 m_host.AddScriptLPS(1); 2530 m_host.AddScriptLPS(1);
2561 m_host.ParentGroup.RootPart.SetAngularImpulse(new Vector3((float)torque.x, (float)torque.y, (float)torque.z), local != 0); 2531 m_host.ParentGroup.RootPart.SetAngularImpulse(torque, local != 0);
2562 } 2532 }
2563 2533
2564 public LSL_Vector llGetTorque() 2534 public LSL_Vector llGetTorque()
@@ -3123,13 +3093,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3123 return; 3093 return;
3124 } 3094 }
3125 3095
3126 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
3127 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z);
3128
3129 // need the magnitude later 3096 // need the magnitude later
3130 // float velmag = (float)Util.GetMagnitude(llvel); 3097 // float velmag = (float)Util.GetMagnitude(llvel);
3131 3098
3132 SceneObjectGroup new_group = World.RezObject(m_host, item, llpos, Rot2Quaternion(rot), llvel, param); 3099 SceneObjectGroup new_group = World.RezObject(m_host, item, pos, rot, vel, param);
3133 3100
3134 // If either of these are null, then there was an unknown error. 3101 // If either of these are null, then there was an unknown error.
3135 if (new_group == null) 3102 if (new_group == null)
@@ -3156,11 +3123,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3156 3123
3157 PhysicsActor pa = new_group.RootPart.PhysActor; 3124 PhysicsActor pa = new_group.RootPart.PhysActor;
3158 3125
3159 if (pa != null && pa.IsPhysical && llvel != Vector3.Zero) 3126 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
3160 { 3127 {
3161 float groupmass = new_group.GetMass(); 3128 float groupmass = new_group.GetMass();
3162 llvel *= -groupmass; 3129 vel *= -groupmass;
3163 llApplyImpulse(new LSL_Vector(llvel.X, llvel.Y,llvel.Z), 0); 3130 llApplyImpulse(vel, 0);
3164 } 3131 }
3165 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) 3132 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
3166 return; 3133 return;
@@ -3211,7 +3178,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3211 return; 3178 return;
3212 } 3179 }
3213 3180
3214 m_host.StartLookAt(Rot2Quaternion(r3 * r2 * r1), (float)strength, (float)damping); 3181 m_host.StartLookAt((Quaternion)(r3 * r2 * r1), (float)strength, (float)damping);
3215 } 3182 }
3216 } 3183 }
3217 3184
@@ -3637,7 +3604,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3637 } 3604 }
3638 else 3605 else
3639 { 3606 {
3640 m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping); 3607 m_host.RotLookAt(target, (float)strength, (float)damping);
3641 } 3608 }
3642 } 3609 }
3643 3610
@@ -3718,7 +3685,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3718 3685
3719 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain) 3686 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
3720 { 3687 {
3721 part.UpdateAngularVelocity(new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate))); 3688 part.UpdateAngularVelocity(axis * spinrate);
3722 } 3689 }
3723 3690
3724 public LSL_Integer llGetStartParameter() 3691 public LSL_Integer llGetStartParameter()
@@ -3932,7 +3899,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3932 try 3899 try
3933 { 3900 {
3934 foreach (SceneObjectPart part in parts) 3901 foreach (SceneObjectPart part in parts)
3935 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 3902 part.SetFaceColorAlpha(face, color, null);
3936 } 3903 }
3937 finally 3904 finally
3938 { 3905 {
@@ -4364,7 +4331,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4364 World.RegionInfo.RegionName+" "+ 4331 World.RegionInfo.RegionName+" "+
4365 m_host.AbsolutePosition.ToString(), 4332 m_host.AbsolutePosition.ToString(),
4366 agentItem.ID, true, m_host.AbsolutePosition, 4333 agentItem.ID, true, m_host.AbsolutePosition,
4367 bucket); 4334 bucket, true);
4368 4335
4369 ScenePresence sp; 4336 ScenePresence sp;
4370 4337
@@ -4402,9 +4369,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4402 public void llSetText(string text, LSL_Vector color, double alpha) 4369 public void llSetText(string text, LSL_Vector color, double alpha)
4403 { 4370 {
4404 m_host.AddScriptLPS(1); 4371 m_host.AddScriptLPS(1);
4405 Vector3 av3 = new Vector3(Util.Clip((float)color.x, 0.0f, 1.0f), 4372 Vector3 av3 = Util.Clip(color, 0.0f, 1.0f);
4406 Util.Clip((float)color.y, 0.0f, 1.0f),
4407 Util.Clip((float)color.z, 0.0f, 1.0f));
4408 if (text.Length > 254) 4373 if (text.Length > 254)
4409 text = text.Remove(254); 4374 text = text.Remove(254);
4410 4375
@@ -4631,14 +4596,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4631 ScriptSleep(5000); 4596 ScriptSleep(5000);
4632 } 4597 }
4633 4598
4634 public void llTeleportAgent(string agent, string destination, LSL_Vector pos, LSL_Vector lookAt) 4599 public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
4635 { 4600 {
4636 m_host.AddScriptLPS(1); 4601 m_host.AddScriptLPS(1);
4637 UUID agentId = new UUID(); 4602 UUID agentId = new UUID();
4638 4603
4639 Vector3 targetPos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
4640 Vector3 targetLookAt = new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z);
4641
4642 if (UUID.TryParse(agent, out agentId)) 4604 if (UUID.TryParse(agent, out agentId))
4643 { 4605 {
4644 ScenePresence presence = World.GetScenePresence(agentId); 4606 ScenePresence presence = World.GetScenePresence(agentId);
@@ -4667,15 +4629,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4667 } 4629 }
4668 } 4630 }
4669 4631
4670 public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector pos, LSL_Vector lookAt) 4632 public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
4671 { 4633 {
4672 m_host.AddScriptLPS(1); 4634 m_host.AddScriptLPS(1);
4673 UUID agentId = new UUID(); 4635 UUID agentId = new UUID();
4674 4636
4675 ulong regionHandle = Utils.UIntsToLong((uint)global_coords.x, (uint)global_coords.y); 4637 ulong regionHandle = Utils.UIntsToLong((uint)global_coords.x, (uint)global_coords.y);
4676 4638
4677 Vector3 targetPos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
4678 Vector3 targetLookAt = new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z);
4679 if (UUID.TryParse(agent, out agentId)) 4639 if (UUID.TryParse(agent, out agentId))
4680 { 4640 {
4681 ScenePresence presence = World.GetScenePresence(agentId); 4641 ScenePresence presence = World.GetScenePresence(agentId);
@@ -4972,7 +4932,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4972 distance_attenuation = 1f / normalized_units; 4932 distance_attenuation = 1f / normalized_units;
4973 } 4933 }
4974 4934
4975 Vector3 applied_linear_impulse = new Vector3((float)impulse.x, (float)impulse.y, (float)impulse.z); 4935 Vector3 applied_linear_impulse = impulse;
4976 { 4936 {
4977 float impulse_length = applied_linear_impulse.Length(); 4937 float impulse_length = applied_linear_impulse.Length();
4978 4938
@@ -5620,25 +5580,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5620 /// separated list. There is a space after 5580 /// separated list. There is a space after
5621 /// each comma. 5581 /// each comma.
5622 /// </summary> 5582 /// </summary>
5623
5624 public LSL_String llList2CSV(LSL_List src) 5583 public LSL_String llList2CSV(LSL_List src)
5625 { 5584 {
5626
5627 string ret = String.Empty;
5628 int x = 0;
5629
5630 m_host.AddScriptLPS(1); 5585 m_host.AddScriptLPS(1);
5631 5586
5632 if (src.Data.Length > 0) 5587 return string.Join(", ",
5633 { 5588 (new List<object>(src.Data)).ConvertAll<string>(o =>
5634 ret = src.Data[x++].ToString(); 5589 {
5635 for (; x < src.Data.Length; x++) 5590 return o.ToString();
5636 { 5591 }).ToArray());
5637 ret += ", "+src.Data[x].ToString();
5638 }
5639 }
5640
5641 return ret;
5642 } 5592 }
5643 5593
5644 /// <summary> 5594 /// <summary>
@@ -5937,27 +5887,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5937 /// Returns the index of the first occurrence of test 5887 /// Returns the index of the first occurrence of test
5938 /// in src. 5888 /// in src.
5939 /// </summary> 5889 /// </summary>
5940 5890 /// <param name="src">Source list</param>
5891 /// <param name="test">List to search for</param>
5892 /// <returns>
5893 /// The index number of the point in src where test was found if it was found.
5894 /// Otherwise returns -1
5895 /// </returns>
5941 public LSL_Integer llListFindList(LSL_List src, LSL_List test) 5896 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
5942 { 5897 {
5943
5944 int index = -1; 5898 int index = -1;
5945 int length = src.Length - test.Length + 1; 5899 int length = src.Length - test.Length + 1;
5946 5900
5947 m_host.AddScriptLPS(1); 5901 m_host.AddScriptLPS(1);
5948 5902
5949 // If either list is empty, do not match 5903 // If either list is empty, do not match
5950
5951 if (src.Length != 0 && test.Length != 0) 5904 if (src.Length != 0 && test.Length != 0)
5952 { 5905 {
5953 for (int i = 0; i < length; i++) 5906 for (int i = 0; i < length; i++)
5954 { 5907 {
5955 if (src.Data[i].Equals(test.Data[0])) 5908 // Why this piece of insanity? This is because most script constants are C# value types (e.g. int)
5909 // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code
5910 // and so the comparison fails even if the LSL_Integer conceptually has the same value.
5911 // Therefore, here we test Equals on both the source and destination objects.
5912 // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)).
5913 if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))
5956 { 5914 {
5957 int j; 5915 int j;
5958 for (j = 1; j < test.Length; j++) 5916 for (j = 1; j < test.Length; j++)
5959 if (!src.Data[i+j].Equals(test.Data[j])) 5917 if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))
5960 break; 5918 break;
5919
5961 if (j == test.Length) 5920 if (j == test.Length)
5962 { 5921 {
5963 index = i; 5922 index = i;
@@ -5968,19 +5927,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5968 } 5927 }
5969 5928
5970 return index; 5929 return index;
5971
5972 } 5930 }
5973 5931
5974 public LSL_String llGetObjectName() 5932 public LSL_String llGetObjectName()
5975 { 5933 {
5976 m_host.AddScriptLPS(1); 5934 m_host.AddScriptLPS(1);
5977 return m_host.Name!=null?m_host.Name:String.Empty; 5935 return m_host.Name !=null ? m_host.Name : String.Empty;
5978 } 5936 }
5979 5937
5980 public void llSetObjectName(string name) 5938 public void llSetObjectName(string name)
5981 { 5939 {
5982 m_host.AddScriptLPS(1); 5940 m_host.AddScriptLPS(1);
5983 m_host.Name = name!=null?name:String.Empty; 5941 m_host.Name = name != null ? name : String.Empty;
5984 } 5942 }
5985 5943
5986 public LSL_String llGetDate() 5944 public LSL_String llGetDate()
@@ -6311,19 +6269,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6311 m_host.AddScriptLPS(1); 6269 m_host.AddScriptLPS(1);
6312 6270
6313 List<SceneObjectPart> parts = GetLinkParts(linknumber); 6271 List<SceneObjectPart> parts = GetLinkParts(linknumber);
6314 if (parts.Count > 0) 6272
6273 try
6315 { 6274 {
6316 try 6275 foreach (SceneObjectPart part in parts)
6317 {
6318 foreach (var part in parts)
6319 {
6320 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
6321 }
6322 }
6323 finally
6324 { 6276 {
6277 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
6325 } 6278 }
6326 } 6279 }
6280 finally
6281 {
6282 }
6327 } 6283 }
6328 6284
6329 private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate) 6285 private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate)
@@ -6541,9 +6497,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6541 6497
6542 //Plug the x,y coordinates of the slope normal into the equation of the plane to get 6498 //Plug the x,y coordinates of the slope normal into the equation of the plane to get
6543 //the height of that point on the plane. The resulting vector gives the slope. 6499 //the height of that point on the plane. The resulting vector gives the slope.
6544 Vector3 vsl = new Vector3(); 6500 Vector3 vsl = vsn;
6545 vsl.X = (float)vsn.x;
6546 vsl.Y = (float)vsn.y;
6547 vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z)); 6501 vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z));
6548 vsl.Normalize(); 6502 vsl.Normalize();
6549 //Normalization might be overkill here 6503 //Normalization might be overkill here
@@ -6554,9 +6508,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6554 public LSL_Vector llGroundNormal(LSL_Vector offset) 6508 public LSL_Vector llGroundNormal(LSL_Vector offset)
6555 { 6509 {
6556 m_host.AddScriptLPS(1); 6510 m_host.AddScriptLPS(1);
6557 Vector3 pos = m_host.GetWorldPosition() + new Vector3((float)offset.x, 6511 Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
6558 (float)offset.y,
6559 (float)offset.z);
6560 // Clamp to valid position 6512 // Clamp to valid position
6561 if (pos.X < 0) 6513 if (pos.X < 0)
6562 pos.X = 0; 6514 pos.X = 0;
@@ -6721,7 +6673,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6721 6673
6722 List<SceneObjectPart> parts = GetLinkParts(linknumber); 6674 List<SceneObjectPart> parts = GetLinkParts(linknumber);
6723 6675
6724 foreach (var part in parts) 6676 foreach (SceneObjectPart part in parts)
6725 { 6677 {
6726 SetParticleSystem(part, rules); 6678 SetParticleSystem(part, rules);
6727 } 6679 }
@@ -6965,16 +6917,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6965 if (m_TransferModule != null) 6917 if (m_TransferModule != null)
6966 { 6918 {
6967 byte[] bucket = new byte[] { (byte)AssetType.Folder }; 6919 byte[] bucket = new byte[] { (byte)AssetType.Folder };
6968 6920
6921 Vector3 pos = m_host.AbsolutePosition;
6922
6969 GridInstantMessage msg = new GridInstantMessage(World, 6923 GridInstantMessage msg = new GridInstantMessage(World,
6970 m_host.UUID, m_host.Name + ", an object owned by " + 6924 m_host.OwnerID, m_host.Name, destID,
6971 resolveName(m_host.OwnerID) + ",", destID,
6972 (byte)InstantMessageDialog.TaskInventoryOffered, 6925 (byte)InstantMessageDialog.TaskInventoryOffered,
6973 false, category + "\n" + m_host.Name + " is located at " + 6926 false, string.Format("'{0}'", category),
6974 World.RegionInfo.RegionName + " " + 6927// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
6975 m_host.AbsolutePosition.ToString(), 6928// false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
6976 folderID, true, m_host.AbsolutePosition, 6929 folderID, false, pos,
6977 bucket); 6930 bucket, false);
6978 6931
6979 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 6932 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
6980 } 6933 }
@@ -7010,8 +6963,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7010 6963
7011 if (!m_host.ParentGroup.IsDeleted) 6964 if (!m_host.ParentGroup.IsDeleted)
7012 { 6965 {
7013 m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, 6966 m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, vec);
7014 new Vector3((float)vec.x, (float)vec.y, (float)vec.z));
7015 } 6967 }
7016 } 6968 }
7017 6969
@@ -7023,7 +6975,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7023 6975
7024 if (!m_host.ParentGroup.IsDeleted) 6976 if (!m_host.ParentGroup.IsDeleted)
7025 { 6977 {
7026 m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, Rot2Quaternion(rot)); 6978 m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, rot);
7027 } 6979 }
7028 } 6980 }
7029 6981
@@ -7053,8 +7005,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7053 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0) 7005 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
7054 rot.s = 1; // ZERO_ROTATION = 0,0,0,1 7006 rot.s = 1; // ZERO_ROTATION = 0,0,0,1
7055 7007
7056 part.SitTargetPosition = new Vector3((float)offset.x, (float)offset.y, (float)offset.z); 7008 part.SitTargetPosition = offset;
7057 part.SitTargetOrientation = Rot2Quaternion(rot); 7009 part.SitTargetOrientation = rot;
7058 part.ParentGroup.HasGroupChanged = true; 7010 part.ParentGroup.HasGroupChanged = true;
7059 } 7011 }
7060 7012
@@ -7157,13 +7109,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7157 public void llSetCameraEyeOffset(LSL_Vector offset) 7109 public void llSetCameraEyeOffset(LSL_Vector offset)
7158 { 7110 {
7159 m_host.AddScriptLPS(1); 7111 m_host.AddScriptLPS(1);
7160 m_host.SetCameraEyeOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z)); 7112 m_host.SetCameraEyeOffset(offset);
7161 } 7113 }
7162 7114
7163 public void llSetCameraAtOffset(LSL_Vector offset) 7115 public void llSetCameraAtOffset(LSL_Vector offset)
7164 { 7116 {
7165 m_host.AddScriptLPS(1); 7117 m_host.AddScriptLPS(1);
7166 m_host.SetCameraAtOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z)); 7118 m_host.SetCameraAtOffset(offset);
7167 } 7119 }
7168 7120
7169 public LSL_String llDumpList2String(LSL_List src, string seperator) 7121 public LSL_String llDumpList2String(LSL_List src, string seperator)
@@ -7185,7 +7137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7185 public LSL_Integer llScriptDanger(LSL_Vector pos) 7137 public LSL_Integer llScriptDanger(LSL_Vector pos)
7186 { 7138 {
7187 m_host.AddScriptLPS(1); 7139 m_host.AddScriptLPS(1);
7188 bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.x, (float)pos.y, (float)pos.z)); 7140 bool result = World.ScriptDanger(m_host.LocalId, pos);
7189 if (result) 7141 if (result)
7190 { 7142 {
7191 return 1; 7143 return 1;
@@ -7767,7 +7719,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7767 { 7719 {
7768 m_host.AddScriptLPS(1); 7720 m_host.AddScriptLPS(1);
7769 7721
7770 setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules); 7722 setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams");
7771 7723
7772 ScriptSleep(200); 7724 ScriptSleep(200);
7773 } 7725 }
@@ -7776,10 +7728,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7776 { 7728 {
7777 m_host.AddScriptLPS(1); 7729 m_host.AddScriptLPS(1);
7778 7730
7779 setLinkPrimParams(linknumber, rules); 7731 setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast");
7732
7733 ScriptSleep(200);
7780 } 7734 }
7781 7735
7782 private void setLinkPrimParams(int linknumber, LSL_List rules) 7736 private void setLinkPrimParams(int linknumber, LSL_List rules, string originFunc)
7783 { 7737 {
7784 List<object> parts = new List<object>(); 7738 List<object> parts = new List<object>();
7785 List<SceneObjectPart> prims = GetLinkParts(linknumber); 7739 List<SceneObjectPart> prims = GetLinkParts(linknumber);
@@ -7790,15 +7744,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7790 parts.Add(p); 7744 parts.Add(p);
7791 7745
7792 LSL_List remaining = null; 7746 LSL_List remaining = null;
7747 uint rulesParsed = 0;
7793 7748
7794 if (parts.Count > 0) 7749 if (parts.Count > 0)
7795 { 7750 {
7796 foreach (object part in parts) 7751 foreach (object part in parts)
7797 { 7752 {
7798 if (part is SceneObjectPart) 7753 if (part is SceneObjectPart)
7799 remaining = SetPrimParams((SceneObjectPart)part, rules); 7754 remaining = SetPrimParams((SceneObjectPart)part, rules, originFunc, ref rulesParsed);
7800 else 7755 else
7801 remaining = SetPrimParams((ScenePresence)part, rules); 7756 remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed);
7802 } 7757 }
7803 7758
7804 while ((object)remaining != null && remaining.Length > 2) 7759 while ((object)remaining != null && remaining.Length > 2)
@@ -7817,9 +7772,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7817 foreach (object part in parts) 7772 foreach (object part in parts)
7818 { 7773 {
7819 if (part is SceneObjectPart) 7774 if (part is SceneObjectPart)
7820 remaining = SetPrimParams((SceneObjectPart)part, rules); 7775 remaining = SetPrimParams((SceneObjectPart)part, rules, originFunc, ref rulesParsed);
7821 else 7776 else
7822 remaining = SetPrimParams((ScenePresence)part, rules); 7777 remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed);
7823 } 7778 }
7824 } 7779 }
7825 } 7780 }
@@ -7857,6 +7812,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7857 7812
7858 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) 7813 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
7859 { 7814 {
7815 setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams");
7860 llSetLinkPrimitiveParamsFast(linknumber, rules); 7816 llSetLinkPrimitiveParamsFast(linknumber, rules);
7861 ScriptSleep(200); 7817 ScriptSleep(200);
7862 } 7818 }
@@ -7884,195 +7840,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7884 return new Vector3((float)x, (float)y, (float)z); 7840 return new Vector3((float)x, (float)y, (float)z);
7885 } 7841 }
7886 7842
7887 protected LSL_List SetPrimParams(ScenePresence av, LSL_List rules) 7843 protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed)
7888 {
7889 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
7890
7891 int idx = 0;
7892
7893 bool positionChanged = false;
7894 Vector3 finalPos = Vector3.Zero;
7895
7896 try
7897 {
7898 while (idx < rules.Length)
7899 {
7900 int code = rules.GetLSLIntegerItem(idx++);
7901
7902 int remain = rules.Length - idx;
7903
7904 switch (code)
7905 {
7906 case (int)ScriptBaseClass.PRIM_POSITION:
7907 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
7908 {
7909 if (remain < 1)
7910 return null;
7911
7912 LSL_Vector v;
7913 v = rules.GetVector3Item(idx++);
7914
7915 SceneObjectPart part = World.GetSceneObjectPart(av.ParentID);
7916 if (part == null)
7917 break;
7918
7919 LSL_Rotation localRot = ScriptBaseClass.ZERO_ROTATION;
7920 LSL_Vector localPos = ScriptBaseClass.ZERO_VECTOR;
7921 if (part.LinkNum > 1)
7922 {
7923 localRot = GetPartLocalRot(part);
7924 localPos = GetPartLocalPos(part);
7925 }
7926
7927 v -= localPos;
7928 v /= localRot;
7929
7930 LSL_Vector sitOffset = (llRot2Up(new LSL_Rotation(av.Rotation.X, av.Rotation.Y, av.Rotation.Z, av.Rotation.W)) * av.Appearance.AvatarHeight * 0.02638f);
7931
7932 v = v + 2 * sitOffset;
7933
7934 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
7935 av.SendAvatarDataToAllAgents();
7936
7937 }
7938 break;
7939
7940 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
7941 case (int)ScriptBaseClass.PRIM_ROTATION:
7942 {
7943 if (remain < 1)
7944 return null;
7945
7946 LSL_Rotation r;
7947 r = rules.GetQuaternionItem(idx++);
7948
7949 SceneObjectPart part = World.GetSceneObjectPart(av.ParentID);
7950 if (part == null)
7951 break;
7952
7953 LSL_Rotation localRot = ScriptBaseClass.ZERO_ROTATION;
7954 LSL_Vector localPos = ScriptBaseClass.ZERO_VECTOR;
7955
7956 if (part.LinkNum > 1)
7957 localRot = GetPartLocalRot(part);
7958
7959 r = r * llGetRootRotation() / localRot;
7960 av.Rotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
7961 av.SendAvatarDataToAllAgents();
7962 }
7963 break;
7964
7965 // parse rest doing nothing but number of parameters error check
7966 case (int)ScriptBaseClass.PRIM_SIZE:
7967 case (int)ScriptBaseClass.PRIM_MATERIAL:
7968 case (int)ScriptBaseClass.PRIM_PHANTOM:
7969 case (int)ScriptBaseClass.PRIM_PHYSICS:
7970 case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
7971 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
7972 case (int)ScriptBaseClass.PRIM_NAME:
7973 case (int)ScriptBaseClass.PRIM_DESC:
7974 if (remain < 1)
7975 return null;
7976 idx++;
7977 break;
7978
7979 case (int)ScriptBaseClass.PRIM_GLOW:
7980 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7981 case (int)ScriptBaseClass.PRIM_TEXGEN:
7982 if (remain < 2)
7983 return null;
7984 idx += 2;
7985 break;
7986
7987 case (int)ScriptBaseClass.PRIM_TYPE:
7988 if (remain < 3)
7989 return null;
7990 code = (int)rules.GetLSLIntegerItem(idx++);
7991 remain = rules.Length - idx;
7992 switch (code)
7993 {
7994 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
7995 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
7996 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
7997 if (remain < 6)
7998 return null;
7999 idx += 6;
8000 break;
8001
8002 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
8003 if (remain < 5)
8004 return null;
8005 idx += 5;
8006 break;
8007
8008 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
8009 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
8010 case (int)ScriptBaseClass.PRIM_TYPE_RING:
8011 if (remain < 11)
8012 return null;
8013 idx += 11;
8014 break;
8015
8016 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
8017 if (remain < 2)
8018 return null;
8019 idx += 2;
8020 break;
8021 }
8022 break;
8023
8024 case (int)ScriptBaseClass.PRIM_COLOR:
8025 case (int)ScriptBaseClass.PRIM_TEXT:
8026 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
8027 case (int)ScriptBaseClass.PRIM_OMEGA:
8028 if (remain < 3)
8029 return null;
8030 idx += 3;
8031 break;
8032
8033 case (int)ScriptBaseClass.PRIM_TEXTURE:
8034 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
8035 case (int)ScriptBaseClass.PRIM_PHYSICS_MATERIAL:
8036 if (remain < 5)
8037 return null;
8038 idx += 5;
8039 break;
8040
8041 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
8042 if (remain < 7)
8043 return null;
8044
8045 idx += 7;
8046 break;
8047
8048 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8049 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
8050 return null;
8051
8052 return rules.GetSublist(idx, -1);
8053 }
8054 }
8055 }
8056
8057 finally
8058 {
8059 if (positionChanged)
8060 {
8061 av.OffsetPosition = finalPos;
8062// av.SendAvatarDataToAllAgents();
8063 av.SendTerseUpdateToAllClients();
8064 positionChanged = false;
8065 }
8066 }
8067 return null;
8068 }
8069
8070 protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules)
8071 { 7844 {
8072 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) 7845 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
8073 return null; 7846 return null;
8074 7847
8075 int idx = 0; 7848 int idx = 0;
7849 int idxStart = 0;
8076 7850
8077 SceneObjectGroup parentgrp = part.ParentGroup; 7851 SceneObjectGroup parentgrp = part.ParentGroup;
8078 7852
@@ -8083,9 +7857,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8083 { 7857 {
8084 while (idx < rules.Length) 7858 while (idx < rules.Length)
8085 { 7859 {
7860 ++rulesParsed;
8086 int code = rules.GetLSLIntegerItem(idx++); 7861 int code = rules.GetLSLIntegerItem(idx++);
8087 7862
8088 int remain = rules.Length - idx; 7863 int remain = rules.Length - idx;
7864 idxStart = idx;
8089 7865
8090 int face; 7866 int face;
8091 LSL_Vector v; 7867 LSL_Vector v;
@@ -8115,18 +7891,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8115 return null; 7891 return null;
8116 7892
8117 LSL_Rotation q = rules.GetQuaternionItem(idx++); 7893 LSL_Rotation q = rules.GetQuaternionItem(idx++);
8118 SceneObjectPart rootPart = parentgrp.RootPart;
8119 // try to let this work as in SL... 7894 // try to let this work as in SL...
8120 if (rootPart == part) 7895 if (part.ParentID == 0)
8121 { 7896 {
8122 // special case: If we are root, rotate complete SOG to new rotation 7897 // special case: If we are root, rotate complete SOG to new rotation
8123 SetRot(part, Rot2Quaternion(q)); 7898 SetRot(part, q);
8124 } 7899 }
8125 else 7900 else
8126 { 7901 {
8127 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask. 7902 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
8128 // sounds like sl bug that we need to replicate 7903 SceneObjectPart rootPart = part.ParentGroup.RootPart;
8129 SetRot(part, rootPart.RotationOffset * Rot2Quaternion(q)); 7904 SetRot(part, rootPart.RotationOffset * (Quaternion)q);
8130 } 7905 }
8131 7906
8132 break; 7907 break;
@@ -8300,8 +8075,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8300 LSL_Vector color=rules.GetVector3Item(idx++); 8075 LSL_Vector color=rules.GetVector3Item(idx++);
8301 double alpha=(double)rules.GetLSLFloatItem(idx++); 8076 double alpha=(double)rules.GetLSLFloatItem(idx++);
8302 8077
8303 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 8078 part.SetFaceColorAlpha(face, color, alpha);
8304 SetAlpha(part, alpha, face);
8305 8079
8306 break; 8080 break;
8307 8081
@@ -8449,9 +8223,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8449 string primText = rules.GetLSLStringItem(idx++); 8223 string primText = rules.GetLSLStringItem(idx++);
8450 LSL_Vector primTextColor = rules.GetVector3Item(idx++); 8224 LSL_Vector primTextColor = rules.GetVector3Item(idx++);
8451 LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++); 8225 LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++);
8452 Vector3 av3 = new Vector3(Util.Clip((float)primTextColor.x, 0.0f, 1.0f), 8226 Vector3 av3 = Util.Clip(primTextColor, 0.0f, 1.0f);
8453 Util.Clip((float)primTextColor.y, 0.0f, 1.0f),
8454 Util.Clip((float)primTextColor.z, 0.0f, 1.0f));
8455 part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f)); 8227 part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f));
8456 8228
8457 break; 8229 break;
@@ -8470,8 +8242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8470 case (int)ScriptBaseClass.PRIM_ROT_LOCAL: 8242 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8471 if (remain < 1) 8243 if (remain < 1)
8472 return null; 8244 return null;
8473 LSL_Rotation lr = rules.GetQuaternionItem(idx++); 8245 SetRot(part, rules.GetQuaternionItem(idx++));
8474 SetRot(part, Rot2Quaternion(lr));
8475 break; 8246 break;
8476 case (int)ScriptBaseClass.PRIM_OMEGA: 8247 case (int)ScriptBaseClass.PRIM_OMEGA:
8477 if (remain < 3) 8248 if (remain < 3)
@@ -8481,7 +8252,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8481 LSL_Float gain = rules.GetLSLFloatItem(idx++); 8252 LSL_Float gain = rules.GetLSLFloatItem(idx++);
8482 TargetOmega(part, axis, (double)spinrate, (double)gain); 8253 TargetOmega(part, axis, (double)spinrate, (double)gain);
8483 break; 8254 break;
8484 8255 case (int)ScriptBaseClass.PRIM_SLICE:
8256 if (remain < 1)
8257 return null;
8258 LSL_Vector slice = rules.GetVector3Item(idx++);
8259 part.UpdateSlice((float)slice.x, (float)slice.y);
8260 break;
8485 case (int)ScriptBaseClass.PRIM_LINK_TARGET: 8261 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8486 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. 8262 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
8487 return null; 8263 return null;
@@ -8490,6 +8266,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8490 } 8266 }
8491 } 8267 }
8492 } 8268 }
8269 catch (InvalidCastException e)
8270 {
8271 ShoutError(string.Format(
8272 "{0} error running rule #{1}: arg #{2} ",
8273 originFunc, rulesParsed, idx - idxStart) + e.Message);
8274 }
8493 finally 8275 finally
8494 { 8276 {
8495 if (positionChanged) 8277 if (positionChanged)
@@ -8498,12 +8280,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8498 { 8280 {
8499 SceneObjectGroup parent = part.ParentGroup; 8281 SceneObjectGroup parent = part.ParentGroup;
8500 Util.FireAndForget(delegate(object x) { 8282 Util.FireAndForget(delegate(object x) {
8501 parent.UpdateGroupPosition(new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z)); 8283 parent.UpdateGroupPosition(currentPosition);
8502 }); 8284 });
8503 } 8285 }
8504 else 8286 else
8505 { 8287 {
8506 part.OffsetPosition = new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z); 8288 part.OffsetPosition = currentPosition;
8507 SceneObjectGroup parent = part.ParentGroup; 8289 SceneObjectGroup parent = part.ParentGroup;
8508 parent.HasGroupChanged = true; 8290 parent.HasGroupChanged = true;
8509 parent.ScheduleGroupForTerseUpdate(); 8291 parent.ScheduleGroupForTerseUpdate();
@@ -8881,7 +8663,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8881 public LSL_List llGetPrimitiveParams(LSL_List rules) 8663 public LSL_List llGetPrimitiveParams(LSL_List rules)
8882 { 8664 {
8883 m_host.AddScriptLPS(1); 8665 m_host.AddScriptLPS(1);
8884 return GetLinkPrimitiveParams(m_host, rules); 8666
8667 LSL_List result = new LSL_List();
8668
8669 LSL_List remaining = GetPrimParams(m_host, rules, ref result);
8670
8671 while (remaining != null && remaining.Length > 2)
8672 {
8673 int linknumber = remaining.GetLSLIntegerItem(0);
8674 rules = remaining.GetSublist(1, -1);
8675 List<SceneObjectPart> parts = GetLinkParts(linknumber);
8676
8677 foreach (SceneObjectPart part in parts)
8678 remaining = GetPrimParams(part, rules, ref result);
8679 }
8680
8681 return result;
8885 } 8682 }
8886 8683
8887 public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules) 8684 public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules)
@@ -8891,294 +8688,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8891 // acording to SL wiki this must indicate a single link number or link_root or link_this. 8688 // acording to SL wiki this must indicate a single link number or link_root or link_this.
8892 // keep other options as before 8689 // keep other options as before
8893 8690
8894 List<SceneObjectPart> parts = GetLinkParts(linknumber); 8691 List<SceneObjectPart> parts;
8895 List<ScenePresence> avatars = GetLinkAvatars(linknumber); 8692 List<ScenePresence> avatars;
8896 8693
8897 LSL_List res = new LSL_List(); 8694 LSL_List res = new LSL_List();
8695 LSL_List remaining = null;
8898 8696
8899 if (parts.Count > 0) 8697 while (rules.Length > 0)
8900 { 8698 {
8901 foreach (var part in parts) 8699 parts = GetLinkParts(linknumber);
8700 avatars = GetLinkAvatars(linknumber);
8701
8702 remaining = null;
8703 foreach (SceneObjectPart part in parts)
8902 { 8704 {
8903 LSL_List partRes = GetLinkPrimitiveParams(part, rules); 8705 remaining = GetPrimParams(part, rules, ref res);
8904 res += partRes;
8905 } 8706 }
8906 }
8907 if (avatars.Count > 0)
8908 {
8909 foreach (ScenePresence avatar in avatars) 8707 foreach (ScenePresence avatar in avatars)
8910 { 8708 {
8911 LSL_List avaRes = GetLinkPrimitiveParams(avatar, rules); 8709 remaining = GetPrimParams(avatar, rules, ref res);
8912 res += avaRes;
8913 } 8710 }
8914 }
8915 return res;
8916 }
8917
8918 public LSL_List GetLinkPrimitiveParams(ScenePresence avatar, LSL_List rules)
8919 {
8920 // avatars case
8921 // replies as SL wiki
8922
8923 LSL_List res = new LSL_List();
8924// SceneObjectPart sitPart = avatar.ParentPart; // most likelly it will be needed
8925 SceneObjectPart sitPart = World.GetSceneObjectPart(avatar.ParentID); // maybe better do this expensive search for it in case it's gone??
8926
8927 int idx = 0;
8928 while (idx < rules.Length)
8929 {
8930 int code = (int)rules.GetLSLIntegerItem(idx++);
8931 int remain = rules.Length - idx;
8932 8711
8933 switch (code) 8712 if (remaining != null && remaining.Length > 0)
8934 { 8713 {
8935 case (int)ScriptBaseClass.PRIM_MATERIAL: 8714 linknumber = remaining.GetLSLIntegerItem(0);
8936 res.Add(new LSL_Integer((int)SOPMaterialData.SopMaterial.Flesh)); 8715 rules = remaining.GetSublist(1, -1);
8937 break;
8938
8939 case (int)ScriptBaseClass.PRIM_PHYSICS:
8940 res.Add(new LSL_Integer(0));
8941 break;
8942
8943 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8944 res.Add(new LSL_Integer(0));
8945 break;
8946
8947 case (int)ScriptBaseClass.PRIM_PHANTOM:
8948 res.Add(new LSL_Integer(0));
8949 break;
8950
8951 case (int)ScriptBaseClass.PRIM_POSITION:
8952
8953 Vector3 pos = avatar.OffsetPosition;
8954
8955 Vector3 sitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f *2.0f);
8956 pos -= sitOffset;
8957
8958 if( sitPart != null)
8959 pos = sitPart.GetWorldPosition() + pos * sitPart.GetWorldRotation();
8960
8961 res.Add(new LSL_Vector(pos.X,pos.Y,pos.Z));
8962 break;
8963
8964 case (int)ScriptBaseClass.PRIM_SIZE:
8965 // as in llGetAgentSize above
8966 res.Add(new LSL_Vector(0.45f, 0.6f, avatar.Appearance.AvatarHeight));
8967 break;
8968
8969 case (int)ScriptBaseClass.PRIM_ROTATION:
8970 Quaternion rot = avatar.Rotation;
8971 if (sitPart != null)
8972 {
8973 rot = sitPart.GetWorldRotation() * rot; // apply sit part world rotation
8974 }
8975
8976 res.Add(new LSL_Rotation (rot.X, rot.Y, rot.Z, rot.W));
8977 break;
8978
8979 case (int)ScriptBaseClass.PRIM_TYPE:
8980 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX));
8981 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT));
8982 res.Add(new LSL_Vector(0f,1.0f,0f));
8983 res.Add(new LSL_Float(0.0f));
8984 res.Add(new LSL_Vector(0, 0, 0));
8985 res.Add(new LSL_Vector(1.0f,1.0f,0f));
8986 res.Add(new LSL_Vector(0, 0, 0));
8987 break;
8988
8989 case (int)ScriptBaseClass.PRIM_TEXTURE:
8990 if (remain < 1)
8991 return res;
8992
8993 int face = (int)rules.GetLSLIntegerItem(idx++);
8994 if (face == ScriptBaseClass.ALL_SIDES)
8995 {
8996 for (face = 0; face < 21; face++)
8997 {
8998 res.Add(new LSL_String(""));
8999 res.Add(new LSL_Vector(0,0,0));
9000 res.Add(new LSL_Vector(0,0,0));
9001 res.Add(new LSL_Float(0.0));
9002 }
9003 }
9004 else
9005 {
9006 if (face >= 0 && face < 21)
9007 {
9008 res.Add(new LSL_String(""));
9009 res.Add(new LSL_Vector(0,0,0));
9010 res.Add(new LSL_Vector(0,0,0));
9011 res.Add(new LSL_Float(0.0));
9012 }
9013 }
9014 break;
9015
9016 case (int)ScriptBaseClass.PRIM_COLOR:
9017 if (remain < 1)
9018 return res;
9019
9020 face = (int)rules.GetLSLIntegerItem(idx++);
9021
9022 if (face == ScriptBaseClass.ALL_SIDES)
9023 {
9024 for (face = 0; face < 21; face++)
9025 {
9026 res.Add(new LSL_Vector(0,0,0));
9027 res.Add(new LSL_Float(0));
9028 }
9029 }
9030 else
9031 {
9032 res.Add(new LSL_Vector(0,0,0));
9033 res.Add(new LSL_Float(0));
9034 }
9035 break;
9036
9037 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
9038 if (remain < 1)
9039 return res;
9040 face = (int)rules.GetLSLIntegerItem(idx++);
9041
9042 if (face == ScriptBaseClass.ALL_SIDES)
9043 {
9044 for (face = 0; face < 21; face++)
9045 {
9046 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
9047 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
9048 }
9049 }
9050 else
9051 {
9052 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
9053 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
9054 }
9055 break;
9056
9057 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
9058 if (remain < 1)
9059 return res;
9060 face = (int)rules.GetLSLIntegerItem(idx++);
9061
9062 if (face == ScriptBaseClass.ALL_SIDES)
9063 {
9064 for (face = 0; face < 21; face++)
9065 {
9066 res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
9067 }
9068 }
9069 else
9070 {
9071 res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
9072 }
9073 break;
9074
9075 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
9076 res.Add(new LSL_Integer(0));
9077 res.Add(new LSL_Integer(0));// softness
9078 res.Add(new LSL_Float(0.0f)); // gravity
9079 res.Add(new LSL_Float(0.0f)); // friction
9080 res.Add(new LSL_Float(0.0f)); // wind
9081 res.Add(new LSL_Float(0.0f)); // tension
9082 res.Add(new LSL_Vector(0f,0f,0f));
9083 break;
9084
9085 case (int)ScriptBaseClass.PRIM_TEXGEN:
9086 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
9087 if (remain < 1)
9088 return res;
9089 face = (int)rules.GetLSLIntegerItem(idx++);
9090
9091 if (face == ScriptBaseClass.ALL_SIDES)
9092 {
9093 for (face = 0; face < 21; face++)
9094 {
9095 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
9096 }
9097 }
9098 else
9099 {
9100 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
9101 }
9102 break;
9103
9104 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
9105 res.Add(new LSL_Integer(0));
9106 res.Add(new LSL_Vector(0f,0f,0f));
9107 res.Add(new LSL_Float(0f)); // intensity
9108 res.Add(new LSL_Float(0f)); // radius
9109 res.Add(new LSL_Float(0f)); // falloff
9110 break;
9111
9112 case (int)ScriptBaseClass.PRIM_GLOW:
9113 if (remain < 1)
9114 return res;
9115 face = (int)rules.GetLSLIntegerItem(idx++);
9116
9117 if (face == ScriptBaseClass.ALL_SIDES)
9118 {
9119 for (face = 0; face < 21; face++)
9120 {
9121 res.Add(new LSL_Float(0f));
9122 }
9123 }
9124 else
9125 {
9126 res.Add(new LSL_Float(0f));
9127 }
9128 break;
9129
9130 case (int)ScriptBaseClass.PRIM_TEXT:
9131 res.Add(new LSL_String(""));
9132 res.Add(new LSL_Vector(0f,0f,0f));
9133 res.Add(new LSL_Float(1.0f));
9134 break;
9135
9136 case (int)ScriptBaseClass.PRIM_NAME:
9137 res.Add(new LSL_String(avatar.Name));
9138 break;
9139
9140 case (int)ScriptBaseClass.PRIM_DESC:
9141 res.Add(new LSL_String(""));
9142 break;
9143
9144 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
9145 Quaternion lrot = avatar.Rotation;
9146
9147 if (sitPart != null && sitPart != sitPart.ParentGroup.RootPart)
9148 {
9149 lrot = sitPart.RotationOffset * lrot; // apply sit part rotation offset
9150 }
9151 res.Add(new LSL_Rotation(lrot.X, lrot.Y, lrot.Z, lrot.W));
9152 break;
9153
9154 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
9155 Vector3 lpos = avatar.OffsetPosition; // pos relative to sit part
9156 Vector3 lsitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f * 2.0f);
9157 lpos -= lsitOffset;
9158
9159 if (sitPart != null && sitPart != sitPart.ParentGroup.RootPart)
9160 {
9161 lpos = sitPart.OffsetPosition + (lpos * sitPart.RotationOffset); // make it relative to root prim
9162 }
9163 res.Add(new LSL_Vector(lpos.X,lpos.Y,lpos.Z));
9164 break;
9165
9166 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
9167 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
9168 return res;
9169 LSL_Integer new_linknumber = rules.GetLSLIntegerItem(idx++);
9170 LSL_List new_rules = rules.GetSublist(idx, -1);
9171
9172 res += llGetLinkPrimitiveParams((int)new_linknumber, new_rules);
9173 return res;
9174 } 8716 }
9175 } 8717 }
8718
9176 return res; 8719 return res;
9177 } 8720 }
9178 8721
9179 public LSL_List GetLinkPrimitiveParams(SceneObjectPart part, LSL_List rules) 8722 public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res)
9180 { 8723 {
9181 LSL_List res = new LSL_List();
9182 int idx=0; 8724 int idx=0;
9183 while (idx < rules.Length) 8725 while (idx < rules.Length)
9184 { 8726 {
@@ -9316,7 +8858,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9316 8858
9317 case (int)ScriptBaseClass.PRIM_TEXTURE: 8859 case (int)ScriptBaseClass.PRIM_TEXTURE:
9318 if (remain < 1) 8860 if (remain < 1)
9319 return res; 8861 return null;
9320 8862
9321 int face = (int)rules.GetLSLIntegerItem(idx++); 8863 int face = (int)rules.GetLSLIntegerItem(idx++);
9322 Primitive.TextureEntry tex = part.Shape.Textures; 8864 Primitive.TextureEntry tex = part.Shape.Textures;
@@ -9356,7 +8898,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9356 8898
9357 case (int)ScriptBaseClass.PRIM_COLOR: 8899 case (int)ScriptBaseClass.PRIM_COLOR:
9358 if (remain < 1) 8900 if (remain < 1)
9359 return res; 8901 return null;
9360 8902
9361 face=(int)rules.GetLSLIntegerItem(idx++); 8903 face=(int)rules.GetLSLIntegerItem(idx++);
9362 8904
@@ -9385,7 +8927,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9385 8927
9386 case (int)ScriptBaseClass.PRIM_BUMP_SHINY: 8928 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
9387 if (remain < 1) 8929 if (remain < 1)
9388 return res; 8930 return null;
8931
9389 face = (int)rules.GetLSLIntegerItem(idx++); 8932 face = (int)rules.GetLSLIntegerItem(idx++);
9390 8933
9391 tex = part.Shape.Textures; 8934 tex = part.Shape.Textures;
@@ -9441,7 +8984,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9441 8984
9442 case (int)ScriptBaseClass.PRIM_FULLBRIGHT: 8985 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
9443 if (remain < 1) 8986 if (remain < 1)
9444 return res; 8987 return null;
8988
9445 face = (int)rules.GetLSLIntegerItem(idx++); 8989 face = (int)rules.GetLSLIntegerItem(idx++);
9446 8990
9447 tex = part.Shape.Textures; 8991 tex = part.Shape.Textures;
@@ -9495,7 +9039,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9495 case (int)ScriptBaseClass.PRIM_TEXGEN: 9039 case (int)ScriptBaseClass.PRIM_TEXGEN:
9496 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR) 9040 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
9497 if (remain < 1) 9041 if (remain < 1)
9498 return res; 9042 return null;
9043
9499 face = (int)rules.GetLSLIntegerItem(idx++); 9044 face = (int)rules.GetLSLIntegerItem(idx++);
9500 9045
9501 tex = part.Shape.Textures; 9046 tex = part.Shape.Textures;
@@ -9543,7 +9088,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9543 9088
9544 case (int)ScriptBaseClass.PRIM_GLOW: 9089 case (int)ScriptBaseClass.PRIM_GLOW:
9545 if (remain < 1) 9090 if (remain < 1)
9546 return res; 9091 return null;
9092
9547 face = (int)rules.GetLSLIntegerItem(idx++); 9093 face = (int)rules.GetLSLIntegerItem(idx++);
9548 9094
9549 tex = part.Shape.Textures; 9095 tex = part.Shape.Textures;
@@ -9587,18 +9133,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9587 case (int)ScriptBaseClass.PRIM_POS_LOCAL: 9133 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
9588 res.Add(new LSL_Vector(GetPartLocalPos(part))); 9134 res.Add(new LSL_Vector(GetPartLocalPos(part)));
9589 break; 9135 break;
9590 9136 case (int)ScriptBaseClass.PRIM_SLICE:
9137 PrimType prim_type = part.GetPrimType();
9138 bool useProfileBeginEnd = (prim_type == PrimType.SPHERE || prim_type == PrimType.TORUS || prim_type == PrimType.TUBE || prim_type == PrimType.RING);
9139 res.Add(new LSL_Vector(
9140 (useProfileBeginEnd ? part.Shape.ProfileBegin : part.Shape.PathBegin) / 50000.0,
9141 1 - (useProfileBeginEnd ? part.Shape.ProfileEnd : part.Shape.PathEnd) / 50000.0,
9142 0
9143 ));
9144 break;
9591 case (int)ScriptBaseClass.PRIM_LINK_TARGET: 9145 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
9592 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. 9146 if(remain < 3)
9593 return res; 9147 return null;
9594 LSL_Integer new_linknumber = rules.GetLSLIntegerItem(idx++); 9148
9595 LSL_List new_rules = rules.GetSublist(idx, -1); 9149 return rules.GetSublist(idx, -1);
9596 LSL_List tres = llGetLinkPrimitiveParams((int)new_linknumber, new_rules);
9597 res += tres;
9598 return res;
9599 } 9150 }
9600 } 9151 }
9601 return res; 9152
9153 return null;
9602 } 9154 }
9603 9155
9604 public LSL_List llGetPrimMediaParams(int face, LSL_List rules) 9156 public LSL_List llGetPrimMediaParams(int face, LSL_List rules)
@@ -10511,11 +10063,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10511 10063
10512 GridRegion info; 10064 GridRegion info;
10513 10065
10514 if (m_ScriptEngine.World.RegionInfo.RegionName == simulator) //Det data for this simulator? 10066 if (World.RegionInfo.RegionName == simulator)
10515 10067 info = new GridRegion(World.RegionInfo);
10516 info = new GridRegion(m_ScriptEngine.World.RegionInfo);
10517 else 10068 else
10518 info = m_ScriptEngine.World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator); 10069 info = World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator);
10519 10070
10520 switch (data) 10071 switch (data)
10521 { 10072 {
@@ -10525,9 +10076,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10525 ScriptSleep(1000); 10076 ScriptSleep(1000);
10526 return UUID.Zero.ToString(); 10077 return UUID.Zero.ToString();
10527 } 10078 }
10528 if (m_ScriptEngine.World.RegionInfo.RegionName != simulator) 10079
10080 bool isHypergridRegion = false;
10081
10082 if (World.RegionInfo.RegionName != simulator && info.RegionSecret != "")
10083 {
10084 // Hypergrid is currently placing real destination region co-ords into RegionSecret.
10085 // But other code can also use this field for a genuine RegionSecret! Therefore, if
10086 // anything is present we need to disambiguate.
10087 //
10088 // FIXME: Hypergrid should be storing this data in a different field.
10089 RegionFlags regionFlags
10090 = (RegionFlags)m_ScriptEngine.World.GridService.GetRegionFlags(
10091 info.ScopeID, info.RegionID);
10092 isHypergridRegion = (regionFlags & RegionFlags.Hyperlink) != 0;
10093 }
10094
10095 if (isHypergridRegion)
10529 { 10096 {
10530 //Hypergrid Region co-ordinates
10531 uint rx = 0, ry = 0; 10097 uint rx = 0, ry = 0;
10532 Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry); 10098 Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry);
10533 10099
@@ -10538,7 +10104,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10538 } 10104 }
10539 else 10105 else
10540 { 10106 {
10541 //Local-cooridnates 10107 // Local grid co-oridnates
10542 reply = new LSL_Vector( 10108 reply = new LSL_Vector(
10543 info.RegionLocX, 10109 info.RegionLocX,
10544 info.RegionLocY, 10110 info.RegionLocY,
@@ -10992,20 +10558,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10992 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString())) 10558 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
10993 { 10559 {
10994 case ParcelMediaCommandEnum.Url: 10560 case ParcelMediaCommandEnum.Url:
10995 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL)); 10561 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaURL));
10996 break; 10562 break;
10997 case ParcelMediaCommandEnum.Desc: 10563 case ParcelMediaCommandEnum.Desc:
10998 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).Description)); 10564 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).Description));
10999 break; 10565 break;
11000 case ParcelMediaCommandEnum.Texture: 10566 case ParcelMediaCommandEnum.Texture:
11001 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaID.ToString())); 10567 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaID.ToString()));
11002 break; 10568 break;
11003 case ParcelMediaCommandEnum.Type: 10569 case ParcelMediaCommandEnum.Type:
11004 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaType)); 10570 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaType));
11005 break; 10571 break;
11006 case ParcelMediaCommandEnum.Size: 10572 case ParcelMediaCommandEnum.Size:
11007 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaWidth)); 10573 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaWidth));
11008 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaHeight)); 10574 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaHeight));
11009 break; 10575 break;
11010 default: 10576 default:
11011 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url; 10577 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
@@ -11175,9 +10741,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11175 ScenePresence avatar = World.GetScenePresence(detectedParams.Key); 10741 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
11176 if (avatar != null) 10742 if (avatar != null)
11177 { 10743 {
11178 avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name, simname, 10744 avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name,
11179 new Vector3((float)pos.x, (float)pos.y, (float)pos.z), 10745 simname, pos, lookAt);
11180 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z));
11181 } 10746 }
11182 10747
11183 ScriptSleep(1000); 10748 ScriptSleep(1000);
@@ -11362,31 +10927,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11362 public LSL_Float llListStatistics(int operation, LSL_List src) 10927 public LSL_Float llListStatistics(int operation, LSL_List src)
11363 { 10928 {
11364 m_host.AddScriptLPS(1); 10929 m_host.AddScriptLPS(1);
11365 LSL_List nums = LSL_List.ToDoubleList(src);
11366 switch (operation) 10930 switch (operation)
11367 { 10931 {
11368 case ScriptBaseClass.LIST_STAT_RANGE: 10932 case ScriptBaseClass.LIST_STAT_RANGE:
11369 return nums.Range(); 10933 return src.Range();
11370 case ScriptBaseClass.LIST_STAT_MIN: 10934 case ScriptBaseClass.LIST_STAT_MIN:
11371 return nums.Min(); 10935 return src.Min();
11372 case ScriptBaseClass.LIST_STAT_MAX: 10936 case ScriptBaseClass.LIST_STAT_MAX:
11373 return nums.Max(); 10937 return src.Max();
11374 case ScriptBaseClass.LIST_STAT_MEAN: 10938 case ScriptBaseClass.LIST_STAT_MEAN:
11375 return nums.Mean(); 10939 return src.Mean();
11376 case ScriptBaseClass.LIST_STAT_MEDIAN: 10940 case ScriptBaseClass.LIST_STAT_MEDIAN:
11377 return nums.Median(); 10941 return LSL_List.ToDoubleList(src).Median();
11378 case ScriptBaseClass.LIST_STAT_NUM_COUNT: 10942 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
11379 return nums.NumericLength(); 10943 return src.NumericLength();
11380 case ScriptBaseClass.LIST_STAT_STD_DEV: 10944 case ScriptBaseClass.LIST_STAT_STD_DEV:
11381 return nums.StdDev(); 10945 return src.StdDev();
11382 case ScriptBaseClass.LIST_STAT_SUM: 10946 case ScriptBaseClass.LIST_STAT_SUM:
11383 return nums.Sum(); 10947 return src.Sum();
11384 case ScriptBaseClass.LIST_STAT_SUM_SQUARES: 10948 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
11385 return nums.SumSqrs(); 10949 return src.SumSqrs();
11386 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN: 10950 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
11387 return nums.GeometricMean(); 10951 return src.GeometricMean();
11388 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN: 10952 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
11389 return nums.HarmonicMean(); 10953 return src.HarmonicMean();
11390 default: 10954 default:
11391 return 0.0; 10955 return 0.0;
11392 } 10956 }
@@ -11744,7 +11308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11744 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param) 11308 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
11745 { 11309 {
11746 m_host.AddScriptLPS(1); 11310 m_host.AddScriptLPS(1);
11747 LandData land = World.GetLandData((float)pos.x, (float)pos.y); 11311 LandData land = World.GetLandData(pos);
11748 if (land == null) 11312 if (land == null)
11749 { 11313 {
11750 return new LSL_List(0); 11314 return new LSL_List(0);
@@ -11912,13 +11476,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11912 else 11476 else
11913 rot = obj.GetWorldRotation(); 11477 rot = obj.GetWorldRotation();
11914 11478
11915 LSL_Rotation objrot = new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); 11479 LSL_Rotation objrot = new LSL_Rotation(rot);
11916 ret.Add(objrot); 11480 ret.Add(objrot);
11917 } 11481 }
11918 break; 11482 break;
11919 case ScriptBaseClass.OBJECT_VELOCITY: 11483 case ScriptBaseClass.OBJECT_VELOCITY:
11920 Vector3 ovel = obj.Velocity; 11484 ret.Add(new LSL_Vector(obj.Velocity));
11921 ret.Add(new LSL_Vector(ovel.X, ovel.Y, ovel.Z));
11922 break; 11485 break;
11923 case ScriptBaseClass.OBJECT_OWNER: 11486 case ScriptBaseClass.OBJECT_OWNER:
11924 ret.Add(new LSL_String(obj.OwnerID.ToString())); 11487 ret.Add(new LSL_String(obj.OwnerID.ToString()));
@@ -12131,7 +11694,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12131 return tid.ToString(); 11694 return tid.ToString();
12132 } 11695 }
12133 11696
12134 public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules) 11697 public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc)
12135 { 11698 {
12136 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); 11699 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
12137 if (obj == null) 11700 if (obj == null)
@@ -12140,28 +11703,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12140 if (obj.OwnerID != m_host.OwnerID) 11703 if (obj.OwnerID != m_host.OwnerID)
12141 return; 11704 return;
12142 11705
12143 LSL_List remaining = SetPrimParams(obj, rules); 11706 uint rulesParsed = 0;
11707 LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed);
12144 11708
12145 while ((object)remaining != null && remaining.Length > 2) 11709 while ((object)remaining != null && remaining.Length > 2)
12146 { 11710 {
12147 LSL_Integer newLink = remaining.GetLSLIntegerItem(0); 11711 LSL_Integer newLink = remaining.GetLSLIntegerItem(0);
12148 LSL_List newrules = remaining.GetSublist(1, -1); 11712 LSL_List newrules = remaining.GetSublist(1, -1);
12149 foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){ 11713 foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){
12150 remaining = SetPrimParams(part, newrules); 11714 remaining = SetPrimParams(part, newrules, originFunc, ref rulesParsed);
12151 } 11715 }
12152 } 11716 }
12153 } 11717 }
12154 11718
12155 public LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules) 11719 public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules)
12156 { 11720 {
12157 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); 11721 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
12158 if (obj == null)
12159 return new LSL_List();
12160 11722
12161 if (obj.OwnerID != m_host.OwnerID) 11723 LSL_List result = new LSL_List();
12162 return new LSL_List(); 11724
11725 if (obj != null && obj.OwnerID != m_host.OwnerID)
11726 {
11727 LSL_List remaining = GetPrimParams(obj, rules, ref result);
11728
11729 while (remaining != null && remaining.Length > 2)
11730 {
11731 int linknumber = remaining.GetLSLIntegerItem(0);
11732 rules = remaining.GetSublist(1, -1);
11733 List<SceneObjectPart> parts = GetLinkParts(linknumber);
11734
11735 foreach (SceneObjectPart part in parts)
11736 remaining = GetPrimParams(part, rules, ref result);
11737 }
11738 }
12163 11739
12164 return GetLinkPrimitiveParams(obj, rules); 11740 return result;
12165 } 11741 }
12166 11742
12167 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link) 11743 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
@@ -12524,8 +12100,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12524 12100
12525 m_host.AddScriptLPS(1); 12101 m_host.AddScriptLPS(1);
12526 12102
12527 Vector3 rayStart = new Vector3((float)start.x, (float)start.y, (float)start.z); 12103 Vector3 rayStart = start;
12528 Vector3 rayEnd = new Vector3((float)end.x, (float)end.y, (float)end.z); 12104 Vector3 rayEnd = end;
12529 Vector3 dir = rayEnd - rayStart; 12105 Vector3 dir = rayEnd - rayStart;
12530 12106
12531 float dist = Vector3.Mag(dir); 12107 float dist = Vector3.Mag(dir);
@@ -13099,6 +12675,455 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13099 } 12675 }
13100 } 12676 }
13101 } 12677 }
12678
12679 protected LSL_List SetPrimParams(ScenePresence av, LSL_List rules, string originFunc, ref uint rulesParsed)
12680 {
12681 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
12682
12683 int idx = 0;
12684 int idxStart = 0;
12685
12686 bool positionChanged = false;
12687 Vector3 finalPos = Vector3.Zero;
12688
12689 try
12690 {
12691 while (idx < rules.Length)
12692 {
12693 ++rulesParsed;
12694 int code = rules.GetLSLIntegerItem(idx++);
12695
12696 int remain = rules.Length - idx;
12697 idxStart = idx;
12698
12699 switch (code)
12700 {
12701 case (int)ScriptBaseClass.PRIM_POSITION:
12702 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
12703 {
12704 if (remain < 1)
12705 return null;
12706
12707 LSL_Vector v;
12708 v = rules.GetVector3Item(idx++);
12709
12710 SceneObjectPart part = World.GetSceneObjectPart(av.ParentID);
12711 if (part == null)
12712 break;
12713
12714 LSL_Rotation localRot = ScriptBaseClass.ZERO_ROTATION;
12715 LSL_Vector localPos = ScriptBaseClass.ZERO_VECTOR;
12716 if (part.LinkNum > 1)
12717 {
12718 localRot = GetPartLocalRot(part);
12719 localPos = GetPartLocalPos(part);
12720 }
12721
12722 v -= localPos;
12723 v /= localRot;
12724
12725 LSL_Vector sitOffset = (llRot2Up(new LSL_Rotation(av.Rotation.X, av.Rotation.Y, av.Rotation.Z, av.Rotation.W)) * av.Appearance.AvatarHeight * 0.02638f);
12726
12727 v = v + 2 * sitOffset;
12728
12729 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
12730 av.SendAvatarDataToAllAgents();
12731
12732 }
12733 break;
12734
12735 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
12736 case (int)ScriptBaseClass.PRIM_ROTATION:
12737 {
12738 if (remain < 1)
12739 return null;
12740
12741 LSL_Rotation r;
12742 r = rules.GetQuaternionItem(idx++);
12743
12744 SceneObjectPart part = World.GetSceneObjectPart(av.ParentID);
12745 if (part == null)
12746 break;
12747
12748 LSL_Rotation localRot = ScriptBaseClass.ZERO_ROTATION;
12749 LSL_Vector localPos = ScriptBaseClass.ZERO_VECTOR;
12750
12751 if (part.LinkNum > 1)
12752 localRot = GetPartLocalRot(part);
12753
12754 r = r * llGetRootRotation() / localRot;
12755 av.Rotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
12756 av.SendAvatarDataToAllAgents();
12757 }
12758 break;
12759
12760 // parse rest doing nothing but number of parameters error check
12761 case (int)ScriptBaseClass.PRIM_SIZE:
12762 case (int)ScriptBaseClass.PRIM_MATERIAL:
12763 case (int)ScriptBaseClass.PRIM_PHANTOM:
12764 case (int)ScriptBaseClass.PRIM_PHYSICS:
12765 case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
12766 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
12767 case (int)ScriptBaseClass.PRIM_NAME:
12768 case (int)ScriptBaseClass.PRIM_DESC:
12769 if (remain < 1)
12770 return null;
12771 idx++;
12772 break;
12773
12774 case (int)ScriptBaseClass.PRIM_GLOW:
12775 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
12776 case (int)ScriptBaseClass.PRIM_TEXGEN:
12777 if (remain < 2)
12778 return null;
12779 idx += 2;
12780 break;
12781
12782 case (int)ScriptBaseClass.PRIM_TYPE:
12783 if (remain < 3)
12784 return null;
12785 code = (int)rules.GetLSLIntegerItem(idx++);
12786 remain = rules.Length - idx;
12787 switch (code)
12788 {
12789 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
12790 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
12791 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
12792 if (remain < 6)
12793 return null;
12794 idx += 6;
12795 break;
12796
12797 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
12798 if (remain < 5)
12799 return null;
12800 idx += 5;
12801 break;
12802
12803 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
12804 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
12805 case (int)ScriptBaseClass.PRIM_TYPE_RING:
12806 if (remain < 11)
12807 return null;
12808 idx += 11;
12809 break;
12810
12811 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
12812 if (remain < 2)
12813 return null;
12814 idx += 2;
12815 break;
12816 }
12817 break;
12818
12819 case (int)ScriptBaseClass.PRIM_COLOR:
12820 case (int)ScriptBaseClass.PRIM_TEXT:
12821 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
12822 case (int)ScriptBaseClass.PRIM_OMEGA:
12823 if (remain < 3)
12824 return null;
12825 idx += 3;
12826 break;
12827
12828 case (int)ScriptBaseClass.PRIM_TEXTURE:
12829 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
12830 case (int)ScriptBaseClass.PRIM_PHYSICS_MATERIAL:
12831 if (remain < 5)
12832 return null;
12833 idx += 5;
12834 break;
12835
12836 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
12837 if (remain < 7)
12838 return null;
12839
12840 idx += 7;
12841 break;
12842
12843 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
12844 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
12845 return null;
12846
12847 return rules.GetSublist(idx, -1);
12848 }
12849 }
12850 }
12851 catch (InvalidCastException e)
12852 {
12853 ShoutError(string.Format(
12854 "{0} error running rule #{1}: arg #{2} ",
12855 originFunc, rulesParsed, idx - idxStart) + e.Message);
12856 }
12857 finally
12858 {
12859 if (positionChanged)
12860 {
12861 av.OffsetPosition = finalPos;
12862// av.SendAvatarDataToAllAgents();
12863 av.SendTerseUpdateToAllClients();
12864 positionChanged = false;
12865 }
12866 }
12867 return null;
12868 }
12869
12870 public LSL_List GetPrimParams(ScenePresence avatar, LSL_List rules, ref LSL_List res)
12871 {
12872 // avatars case
12873 // replies as SL wiki
12874
12875// SceneObjectPart sitPart = avatar.ParentPart; // most likelly it will be needed
12876 SceneObjectPart sitPart = World.GetSceneObjectPart(avatar.ParentID); // maybe better do this expensive search for it in case it's gone??
12877
12878 int idx = 0;
12879 while (idx < rules.Length)
12880 {
12881 int code = (int)rules.GetLSLIntegerItem(idx++);
12882 int remain = rules.Length - idx;
12883
12884 switch (code)
12885 {
12886 case (int)ScriptBaseClass.PRIM_MATERIAL:
12887 res.Add(new LSL_Integer((int)SOPMaterialData.SopMaterial.Flesh));
12888 break;
12889
12890 case (int)ScriptBaseClass.PRIM_PHYSICS:
12891 res.Add(new LSL_Integer(0));
12892 break;
12893
12894 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
12895 res.Add(new LSL_Integer(0));
12896 break;
12897
12898 case (int)ScriptBaseClass.PRIM_PHANTOM:
12899 res.Add(new LSL_Integer(0));
12900 break;
12901
12902 case (int)ScriptBaseClass.PRIM_POSITION:
12903
12904 Vector3 pos = avatar.OffsetPosition;
12905
12906 Vector3 sitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f *2.0f);
12907 pos -= sitOffset;
12908
12909 if( sitPart != null)
12910 pos = sitPart.GetWorldPosition() + pos * sitPart.GetWorldRotation();
12911
12912 res.Add(new LSL_Vector(pos.X,pos.Y,pos.Z));
12913 break;
12914
12915 case (int)ScriptBaseClass.PRIM_SIZE:
12916 // as in llGetAgentSize above
12917 res.Add(new LSL_Vector(0.45f, 0.6f, avatar.Appearance.AvatarHeight));
12918 break;
12919
12920 case (int)ScriptBaseClass.PRIM_ROTATION:
12921 Quaternion rot = avatar.Rotation;
12922 if (sitPart != null)
12923 {
12924 rot = sitPart.GetWorldRotation() * rot; // apply sit part world rotation
12925 }
12926
12927 res.Add(new LSL_Rotation (rot.X, rot.Y, rot.Z, rot.W));
12928 break;
12929
12930 case (int)ScriptBaseClass.PRIM_TYPE:
12931 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX));
12932 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT));
12933 res.Add(new LSL_Vector(0f,1.0f,0f));
12934 res.Add(new LSL_Float(0.0f));
12935 res.Add(new LSL_Vector(0, 0, 0));
12936 res.Add(new LSL_Vector(1.0f,1.0f,0f));
12937 res.Add(new LSL_Vector(0, 0, 0));
12938 break;
12939
12940 case (int)ScriptBaseClass.PRIM_TEXTURE:
12941 if (remain < 1)
12942 return null;
12943
12944 int face = (int)rules.GetLSLIntegerItem(idx++);
12945 if (face == ScriptBaseClass.ALL_SIDES)
12946 {
12947 for (face = 0; face < 21; face++)
12948 {
12949 res.Add(new LSL_String(""));
12950 res.Add(new LSL_Vector(0,0,0));
12951 res.Add(new LSL_Vector(0,0,0));
12952 res.Add(new LSL_Float(0.0));
12953 }
12954 }
12955 else
12956 {
12957 if (face >= 0 && face < 21)
12958 {
12959 res.Add(new LSL_String(""));
12960 res.Add(new LSL_Vector(0,0,0));
12961 res.Add(new LSL_Vector(0,0,0));
12962 res.Add(new LSL_Float(0.0));
12963 }
12964 }
12965 break;
12966
12967 case (int)ScriptBaseClass.PRIM_COLOR:
12968 if (remain < 1)
12969 return null;
12970
12971 face = (int)rules.GetLSLIntegerItem(idx++);
12972
12973 if (face == ScriptBaseClass.ALL_SIDES)
12974 {
12975 for (face = 0; face < 21; face++)
12976 {
12977 res.Add(new LSL_Vector(0,0,0));
12978 res.Add(new LSL_Float(0));
12979 }
12980 }
12981 else
12982 {
12983 res.Add(new LSL_Vector(0,0,0));
12984 res.Add(new LSL_Float(0));
12985 }
12986 break;
12987
12988 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
12989 if (remain < 1)
12990 return null;
12991 face = (int)rules.GetLSLIntegerItem(idx++);
12992
12993 if (face == ScriptBaseClass.ALL_SIDES)
12994 {
12995 for (face = 0; face < 21; face++)
12996 {
12997 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
12998 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
12999 }
13000 }
13001 else
13002 {
13003 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
13004 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
13005 }
13006 break;
13007
13008 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
13009 if (remain < 1)
13010 return null;
13011 face = (int)rules.GetLSLIntegerItem(idx++);
13012
13013 if (face == ScriptBaseClass.ALL_SIDES)
13014 {
13015 for (face = 0; face < 21; face++)
13016 {
13017 res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
13018 }
13019 }
13020 else
13021 {
13022 res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
13023 }
13024 break;
13025
13026 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
13027 res.Add(new LSL_Integer(0));
13028 res.Add(new LSL_Integer(0));// softness
13029 res.Add(new LSL_Float(0.0f)); // gravity
13030 res.Add(new LSL_Float(0.0f)); // friction
13031 res.Add(new LSL_Float(0.0f)); // wind
13032 res.Add(new LSL_Float(0.0f)); // tension
13033 res.Add(new LSL_Vector(0f,0f,0f));
13034 break;
13035
13036 case (int)ScriptBaseClass.PRIM_TEXGEN:
13037 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
13038 if (remain < 1)
13039 return null;
13040 face = (int)rules.GetLSLIntegerItem(idx++);
13041
13042 if (face == ScriptBaseClass.ALL_SIDES)
13043 {
13044 for (face = 0; face < 21; face++)
13045 {
13046 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
13047 }
13048 }
13049 else
13050 {
13051 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
13052 }
13053 break;
13054
13055 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
13056 res.Add(new LSL_Integer(0));
13057 res.Add(new LSL_Vector(0f,0f,0f));
13058 res.Add(new LSL_Float(0f)); // intensity
13059 res.Add(new LSL_Float(0f)); // radius
13060 res.Add(new LSL_Float(0f)); // falloff
13061 break;
13062
13063 case (int)ScriptBaseClass.PRIM_GLOW:
13064 if (remain < 1)
13065 return null;
13066 face = (int)rules.GetLSLIntegerItem(idx++);
13067
13068 if (face == ScriptBaseClass.ALL_SIDES)
13069 {
13070 for (face = 0; face < 21; face++)
13071 {
13072 res.Add(new LSL_Float(0f));
13073 }
13074 }
13075 else
13076 {
13077 res.Add(new LSL_Float(0f));
13078 }
13079 break;
13080
13081 case (int)ScriptBaseClass.PRIM_TEXT:
13082 res.Add(new LSL_String(""));
13083 res.Add(new LSL_Vector(0f,0f,0f));
13084 res.Add(new LSL_Float(1.0f));
13085 break;
13086
13087 case (int)ScriptBaseClass.PRIM_NAME:
13088 res.Add(new LSL_String(avatar.Name));
13089 break;
13090
13091 case (int)ScriptBaseClass.PRIM_DESC:
13092 res.Add(new LSL_String(""));
13093 break;
13094
13095 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
13096 Quaternion lrot = avatar.Rotation;
13097
13098 if (sitPart != null && sitPart != sitPart.ParentGroup.RootPart)
13099 {
13100 lrot = sitPart.RotationOffset * lrot; // apply sit part rotation offset
13101 }
13102 res.Add(new LSL_Rotation(lrot.X, lrot.Y, lrot.Z, lrot.W));
13103 break;
13104
13105 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
13106 Vector3 lpos = avatar.OffsetPosition; // pos relative to sit part
13107 Vector3 lsitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f * 2.0f);
13108 lpos -= lsitOffset;
13109
13110 if (sitPart != null && sitPart != sitPart.ParentGroup.RootPart)
13111 {
13112 lpos = sitPart.OffsetPosition + (lpos * sitPart.RotationOffset); // make it relative to root prim
13113 }
13114 res.Add(new LSL_Vector(lpos.X,lpos.Y,lpos.Z));
13115 break;
13116
13117 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
13118 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
13119 return null;
13120
13121 return rules.GetSublist(idx, -1);
13122 }
13123 }
13124
13125 return null;
13126 }
13102 } 13127 }
13103 13128
13104 public class NotecardCache 13129 public class NotecardCache
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
index 795de80..ceb4660 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
@@ -304,7 +304,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
304 case (int)ScriptBaseClass.WL_CLOUD_DETAIL_XY_DENSITY: 304 case (int)ScriptBaseClass.WL_CLOUD_DETAIL_XY_DENSITY:
305 idx++; 305 idx++;
306 iV = rules.GetVector3Item(idx); 306 iV = rules.GetVector3Item(idx);
307 wl.cloudDetailXYDensity = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); 307 wl.cloudDetailXYDensity = iV;
308 break; 308 break;
309 case (int)ScriptBaseClass.WL_CLOUD_SCALE: 309 case (int)ScriptBaseClass.WL_CLOUD_SCALE:
310 idx++; 310 idx++;
@@ -329,7 +329,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
329 case (int)ScriptBaseClass.WL_CLOUD_XY_DENSITY: 329 case (int)ScriptBaseClass.WL_CLOUD_XY_DENSITY:
330 idx++; 330 idx++;
331 iV = rules.GetVector3Item(idx); 331 iV = rules.GetVector3Item(idx);
332 wl.cloudXYDensity = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); 332 wl.cloudXYDensity = iV;
333 break; 333 break;
334 case (int)ScriptBaseClass.WL_DENSITY_MULTIPLIER: 334 case (int)ScriptBaseClass.WL_DENSITY_MULTIPLIER:
335 idx++; 335 idx++;
@@ -384,7 +384,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
384 case (int)ScriptBaseClass.WL_REFLECTION_WAVELET_SCALE: 384 case (int)ScriptBaseClass.WL_REFLECTION_WAVELET_SCALE:
385 idx++; 385 idx++;
386 iV = rules.GetVector3Item(idx); 386 iV = rules.GetVector3Item(idx);
387 wl.reflectionWaveletScale = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); 387 wl.reflectionWaveletScale = iV;
388 break; 388 break;
389 case (int)ScriptBaseClass.WL_REFRACT_SCALE_ABOVE: 389 case (int)ScriptBaseClass.WL_REFRACT_SCALE_ABOVE:
390 idx++; 390 idx++;
@@ -422,7 +422,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
422 case (int)ScriptBaseClass.WL_WATER_COLOR: 422 case (int)ScriptBaseClass.WL_WATER_COLOR:
423 idx++; 423 idx++;
424 iV = rules.GetVector3Item(idx); 424 iV = rules.GetVector3Item(idx);
425 wl.waterColor = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); 425 wl.waterColor = iV;
426 break; 426 break;
427 case (int)ScriptBaseClass.WL_WATER_FOG_DENSITY_EXPONENT: 427 case (int)ScriptBaseClass.WL_WATER_FOG_DENSITY_EXPONENT:
428 idx++; 428 idx++;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
index 7844c75..6809c09 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -254,7 +254,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
254 254
255 object[] convertedParms = new object[parms.Length]; 255 object[] convertedParms = new object[parms.Length];
256 for (int i = 0; i < parms.Length; i++) 256 for (int i = 0; i < parms.Length; i++)
257 convertedParms[i] = ConvertFromLSL(parms[i],signature[i]); 257 convertedParms[i] = ConvertFromLSL(parms[i],signature[i], fname);
258 258
259 // now call the function, the contract with the function is that it will always return 259 // now call the function, the contract with the function is that it will always return
260 // non-null but don't trust it completely 260 // non-null but don't trust it completely
@@ -294,7 +294,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
294 294
295 /// <summary> 295 /// <summary>
296 /// </summary> 296 /// </summary>
297 protected object ConvertFromLSL(object lslparm, Type type) 297 protected object ConvertFromLSL(object lslparm, Type type, string fname)
298 { 298 {
299 // ---------- String ---------- 299 // ---------- String ----------
300 if (lslparm is LSL_String) 300 if (lslparm is LSL_String)
@@ -310,7 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
310 // ---------- Integer ---------- 310 // ---------- Integer ----------
311 else if (lslparm is LSL_Integer) 311 else if (lslparm is LSL_Integer)
312 { 312 {
313 if (type == typeof(int)) 313 if (type == typeof(int) || type == typeof(float))
314 return (int)(LSL_Integer)lslparm; 314 return (int)(LSL_Integer)lslparm;
315 } 315 }
316 316
@@ -333,8 +333,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
333 { 333 {
334 if (type == typeof(OpenMetaverse.Quaternion)) 334 if (type == typeof(OpenMetaverse.Quaternion))
335 { 335 {
336 LSL_Rotation rot = (LSL_Rotation)lslparm; 336 return (OpenMetaverse.Quaternion)((LSL_Rotation)lslparm);
337 return new OpenMetaverse.Quaternion((float)rot.x,(float)rot.y,(float)rot.z,(float)rot.s);
338 } 337 }
339 } 338 }
340 339
@@ -343,8 +342,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
343 { 342 {
344 if (type == typeof(OpenMetaverse.Vector3)) 343 if (type == typeof(OpenMetaverse.Vector3))
345 { 344 {
346 LSL_Vector vect = (LSL_Vector)lslparm; 345 return (OpenMetaverse.Vector3)((LSL_Vector)lslparm);
347 return new OpenMetaverse.Vector3((float)vect.x,(float)vect.y,(float)vect.z);
348 } 346 }
349 } 347 }
350 348
@@ -367,23 +365,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
367 result[i] = new UUID((LSL_Key)plist[i]); 365 result[i] = new UUID((LSL_Key)plist[i]);
368 else if (plist[i] is LSL_Rotation) 366 else if (plist[i] is LSL_Rotation)
369 { 367 {
370 LSL_Rotation rot = (LSL_Rotation)plist[i]; 368 result[i] = (OpenMetaverse.Quaternion)(
371 result[i] = new OpenMetaverse.Quaternion((float)rot.x,(float)rot.y,(float)rot.z,(float)rot.s); 369 (LSL_Rotation)plist[i]);
372 } 370 }
373 else if (plist[i] is LSL_Vector) 371 else if (plist[i] is LSL_Vector)
374 { 372 {
375 LSL_Vector vect = (LSL_Vector)plist[i]; 373 result[i] = (OpenMetaverse.Vector3)(
376 result[i] = new OpenMetaverse.Vector3((float)vect.x,(float)vect.y,(float)vect.z); 374 (LSL_Vector)plist[i]);
377 } 375 }
378 else 376 else
379 MODError("unknown LSL list element type"); 377 MODError(String.Format("{0}: unknown LSL list element type", fname));
380 } 378 }
381 379
382 return result; 380 return result;
383 } 381 }
384 } 382 }
385 383
386 MODError(String.Format("parameter type mismatch; expecting {0}",type.Name)); 384 MODError(String.Format("{1}: parameter type mismatch; expecting {0}",type.Name, fname));
387 return null; 385 return null;
388 } 386 }
389 387
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 80111f9..17277d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -141,6 +141,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
141 internal bool m_debuggerSafe = false; 141 internal bool m_debuggerSafe = false;
142 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >(); 142 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >();
143 143
144 protected IUrlModule m_UrlModule = null;
145
144 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 146 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item)
145 { 147 {
146 m_ScriptEngine = ScriptEngine; 148 m_ScriptEngine = ScriptEngine;
@@ -148,6 +150,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
148 m_item = item; 150 m_item = item;
149 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); 151 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
150 152
153 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
154
151 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) 155 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false))
152 m_OSFunctionsEnabled = true; 156 m_OSFunctionsEnabled = true;
153 157
@@ -782,10 +786,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
782 786
783 // We will launch the teleport on a new thread so that when the script threads are terminated 787 // We will launch the teleport on a new thread so that when the script threads are terminated
784 // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. 788 // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting.
785 Util.FireAndForget( 789 Util.FireAndForget(o => World.RequestTeleportLocation(
786 o => World.RequestTeleportLocation(presence.ControllingClient, regionName, 790 presence.ControllingClient, regionName, position,
787 new Vector3((float)position.x, (float)position.y, (float)position.z), 791 lookat, (uint)TPFlags.ViaLocation));
788 new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation));
789 792
790 ScriptSleep(5000); 793 ScriptSleep(5000);
791 794
@@ -828,10 +831,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
828 831
829 // We will launch the teleport on a new thread so that when the script threads are terminated 832 // We will launch the teleport on a new thread so that when the script threads are terminated
830 // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. 833 // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting.
831 Util.FireAndForget( 834 Util.FireAndForget(o => World.RequestTeleportLocation(
832 o => World.RequestTeleportLocation(presence.ControllingClient, regionHandle, 835 presence.ControllingClient, regionHandle,
833 new Vector3((float)position.x, (float)position.y, (float)position.z), 836 position, lookat, (uint)TPFlags.ViaLocation));
834 new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation));
835 837
836 ScriptSleep(5000); 838 ScriptSleep(5000);
837 839
@@ -1680,6 +1682,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1680 return; 1682 return;
1681 } 1683 }
1682 1684
1685 MessageObject(objUUID, message);
1686 }
1687
1688 private void MessageObject(UUID objUUID, string message)
1689 {
1683 object[] resobj = new object[] { new LSL_Types.LSLString(m_host.UUID.ToString()), new LSL_Types.LSLString(message) }; 1690 object[] resobj = new object[] { new LSL_Types.LSLString(m_host.UUID.ToString()), new LSL_Types.LSLString(message) };
1684 1691
1685 SceneObjectPart sceneOP = World.GetSceneObjectPart(objUUID); 1692 SceneObjectPart sceneOP = World.GetSceneObjectPart(objUUID);
@@ -2259,11 +2266,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2259 CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams"); 2266 CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams");
2260 m_host.AddScriptLPS(1); 2267 m_host.AddScriptLPS(1);
2261 InitLSL(); 2268 InitLSL();
2269 // One needs to cast m_LSL_Api because we're using functions not
2270 // on the ILSL_Api interface.
2271 LSL_Api LSL_Api = (LSL_Api)m_LSL_Api;
2262 LSL_List retVal = new LSL_List(); 2272 LSL_List retVal = new LSL_List();
2263 List<SceneObjectPart> parts = ((LSL_Api)m_LSL_Api).GetLinkParts(linknumber); 2273 LSL_List remaining = null;
2274 List<SceneObjectPart> parts = LSL_Api.GetLinkParts(linknumber);
2264 foreach (SceneObjectPart part in parts) 2275 foreach (SceneObjectPart part in parts)
2265 { 2276 {
2266 retVal += ((LSL_Api)m_LSL_Api).GetLinkPrimitiveParams(part, rules); 2277 remaining = LSL_Api.GetPrimParams(part, rules, ref retVal);
2278 }
2279
2280 while (remaining != null && remaining.Length > 2)
2281 {
2282 linknumber = remaining.GetLSLIntegerItem(0);
2283 rules = remaining.GetSublist(1, -1);
2284 parts = LSL_Api.GetLinkParts(linknumber);
2285
2286 foreach (SceneObjectPart part in parts)
2287 remaining = LSL_Api.GetPrimParams(part, rules, ref retVal);
2267 } 2288 }
2268 return retVal; 2289 return retVal;
2269 } 2290 }
@@ -2362,7 +2383,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2362 ownerID = m_host.OwnerID; 2383 ownerID = m_host.OwnerID;
2363 UUID x = module.CreateNPC(firstname, 2384 UUID x = module.CreateNPC(firstname,
2364 lastname, 2385 lastname,
2365 new Vector3((float) position.x, (float) position.y, (float) position.z), 2386 position,
2366 ownerID, 2387 ownerID,
2367 senseAsAgent, 2388 senseAsAgent,
2368 World, 2389 World,
@@ -2485,7 +2506,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2485 return new LSL_Vector(0, 0, 0); 2506 return new LSL_Vector(0, 0, 0);
2486 } 2507 }
2487 2508
2488 public void osNpcMoveTo(LSL_Key npc, LSL_Vector position) 2509 public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
2489 { 2510 {
2490 CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); 2511 CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo");
2491 m_host.AddScriptLPS(1); 2512 m_host.AddScriptLPS(1);
@@ -2500,7 +2521,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2500 if (!module.CheckPermissions(npcId, m_host.OwnerID)) 2521 if (!module.CheckPermissions(npcId, m_host.OwnerID))
2501 return; 2522 return;
2502 2523
2503 Vector3 pos = new Vector3((float) position.x, (float) position.y, (float) position.z);
2504 module.MoveToTarget(npcId, World, pos, false, true, false); 2524 module.MoveToTarget(npcId, World, pos, false, true, false);
2505 } 2525 }
2506 } 2526 }
@@ -2520,11 +2540,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2520 if (!module.CheckPermissions(npcId, m_host.OwnerID)) 2540 if (!module.CheckPermissions(npcId, m_host.OwnerID))
2521 return; 2541 return;
2522 2542
2523 Vector3 pos = new Vector3((float)target.x, (float)target.y, (float)target.z);
2524 module.MoveToTarget( 2543 module.MoveToTarget(
2525 new UUID(npc.m_string), 2544 new UUID(npc.m_string),
2526 World, 2545 World,
2527 pos, 2546 target,
2528 (options & ScriptBaseClass.OS_NPC_NO_FLY) != 0, 2547 (options & ScriptBaseClass.OS_NPC_NO_FLY) != 0,
2529 (options & ScriptBaseClass.OS_NPC_LAND_AT_TARGET) != 0, 2548 (options & ScriptBaseClass.OS_NPC_LAND_AT_TARGET) != 0,
2530 (options & ScriptBaseClass.OS_NPC_RUNNING) != 0); 2549 (options & ScriptBaseClass.OS_NPC_RUNNING) != 0);
@@ -2576,7 +2595,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2576 ScenePresence sp = World.GetScenePresence(npcId); 2595 ScenePresence sp = World.GetScenePresence(npcId);
2577 2596
2578 if (sp != null) 2597 if (sp != null)
2579 sp.Rotation = LSL_Api.Rot2Quaternion(rotation); 2598 sp.Rotation = rotation;
2580 } 2599 }
2581 } 2600 }
2582 2601
@@ -2936,7 +2955,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2936 avatar.SpeedModifier = (float)SpeedModifier; 2955 avatar.SpeedModifier = (float)SpeedModifier;
2937 } 2956 }
2938 2957
2939 public void osKickAvatar(string FirstName,string SurName,string alert) 2958 public void osKickAvatar(string FirstName, string SurName, string alert)
2940 { 2959 {
2941 CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); 2960 CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar");
2942 m_host.AddScriptLPS(1); 2961 m_host.AddScriptLPS(1);
@@ -2950,10 +2969,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2950 sp.ControllingClient.Kick(alert); 2969 sp.ControllingClient.Kick(alert);
2951 2970
2952 // ...and close on our side 2971 // ...and close on our side
2953 sp.Scene.IncomingCloseAgent(sp.UUID); 2972 sp.Scene.IncomingCloseAgent(sp.UUID, false);
2954 } 2973 }
2955 }); 2974 });
2956 } 2975 }
2976
2977 public LSL_Float osGetHealth(string avatar)
2978 {
2979 CheckThreatLevel(ThreatLevel.None, "osGetHealth");
2980 m_host.AddScriptLPS(1);
2981
2982 LSL_Float health = new LSL_Float(-1);
2983 ScenePresence presence = World.GetScenePresence(new UUID(avatar));
2984 if (presence != null) health = presence.Health;
2985 return health;
2986 }
2957 2987
2958 public void osCauseDamage(string avatar, double damage) 2988 public void osCauseDamage(string avatar, double damage)
2959 { 2989 {
@@ -2966,7 +2996,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2966 ScenePresence presence = World.GetScenePresence(avatarId); 2996 ScenePresence presence = World.GetScenePresence(avatarId);
2967 if (presence != null) 2997 if (presence != null)
2968 { 2998 {
2969 LandData land = World.GetLandData((float)pos.X, (float)pos.Y); 2999 LandData land = World.GetLandData(pos);
2970 if ((land.Flags & (uint)ParcelFlags.AllowDamage) == (uint)ParcelFlags.AllowDamage) 3000 if ((land.Flags & (uint)ParcelFlags.AllowDamage) == (uint)ParcelFlags.AllowDamage)
2971 { 3001 {
2972 float health = presence.Health; 3002 float health = presence.Health;
@@ -3013,7 +3043,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3013 m_host.AddScriptLPS(1); 3043 m_host.AddScriptLPS(1);
3014 InitLSL(); 3044 InitLSL();
3015 3045
3016 return m_LSL_Api.GetLinkPrimitiveParamsEx(prim, rules); 3046 return m_LSL_Api.GetPrimitiveParamsEx(prim, rules);
3017 } 3047 }
3018 3048
3019 public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) 3049 public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules)
@@ -3022,7 +3052,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3022 m_host.AddScriptLPS(1); 3052 m_host.AddScriptLPS(1);
3023 InitLSL(); 3053 InitLSL();
3024 3054
3025 m_LSL_Api.SetPrimitiveParamsEx(prim, rules); 3055 m_LSL_Api.SetPrimitiveParamsEx(prim, rules, "osSetPrimitiveParams");
3026 } 3056 }
3027 3057
3028 /// <summary> 3058 /// <summary>
@@ -3254,6 +3284,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3254 } 3284 }
3255 } 3285 }
3256 3286
3287 #region Attachment commands
3288
3257 public void osForceAttachToAvatar(int attachmentPoint) 3289 public void osForceAttachToAvatar(int attachmentPoint)
3258 { 3290 {
3259 CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar"); 3291 CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar");
@@ -3343,6 +3375,175 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3343 ((LSL_Api)m_LSL_Api).DetachFromAvatar(); 3375 ((LSL_Api)m_LSL_Api).DetachFromAvatar();
3344 } 3376 }
3345 3377
3378 public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints)
3379 {
3380 CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments");
3381
3382 m_host.AddScriptLPS(1);
3383
3384 UUID targetUUID;
3385 ScenePresence target;
3386 LSL_List resp = new LSL_List();
3387
3388 if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target))
3389 {
3390 foreach (object point in attachmentPoints.Data)
3391 {
3392 LSL_Integer ipoint = new LSL_Integer(
3393 (point is LSL_Integer || point is int || point is uint) ?
3394 (int)point :
3395 0
3396 );
3397 resp.Add(ipoint);
3398 if (ipoint == 0)
3399 {
3400 // indicates zero attachments
3401 resp.Add(new LSL_Integer(0));
3402 }
3403 else
3404 {
3405 // gets the number of attachments on the attachment point
3406 resp.Add(new LSL_Integer(target.GetAttachments((uint)ipoint).Count));
3407 }
3408 }
3409 }
3410
3411 return resp;
3412 }
3413
3414 public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int options)
3415 {
3416 CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments");
3417 m_host.AddScriptLPS(1);
3418
3419 UUID targetUUID;
3420 ScenePresence target;
3421
3422 if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target))
3423 {
3424 List<int> aps = new List<int>();
3425 foreach (object point in attachmentPoints.Data)
3426 {
3427 int ipoint;
3428 if (int.TryParse(point.ToString(), out ipoint))
3429 {
3430 aps.Add(ipoint);
3431 }
3432 }
3433
3434 List<SceneObjectGroup> attachments = new List<SceneObjectGroup>();
3435
3436 bool msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL);
3437 bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0;
3438
3439 if (msgAll && invertPoints)
3440 {
3441 return;
3442 }
3443 else if (msgAll || invertPoints)
3444 {
3445 attachments = target.GetAttachments();
3446 }
3447 else
3448 {
3449 foreach (int point in aps)
3450 {
3451 if (point > 0)
3452 {
3453 attachments.AddRange(target.GetAttachments((uint)point));
3454 }
3455 }
3456 }
3457
3458 // if we have no attachments at this point, exit now
3459 if (attachments.Count == 0)
3460 {
3461 return;
3462 }
3463
3464 List<SceneObjectGroup> ignoreThese = new List<SceneObjectGroup>();
3465
3466 if (invertPoints)
3467 {
3468 foreach (SceneObjectGroup attachment in attachments)
3469 {
3470 if (aps.Contains((int)attachment.AttachmentPoint))
3471 {
3472 ignoreThese.Add(attachment);
3473 }
3474 }
3475 }
3476
3477 foreach (SceneObjectGroup attachment in ignoreThese)
3478 {
3479 attachments.Remove(attachment);
3480 }
3481 ignoreThese.Clear();
3482
3483 // if inverting removed all attachments to check, exit now
3484 if (attachments.Count < 1)
3485 {
3486 return;
3487 }
3488
3489 if ((options & ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0)
3490 {
3491 foreach (SceneObjectGroup attachment in attachments)
3492 {
3493 if (attachment.RootPart.CreatorID != m_host.CreatorID)
3494 {
3495 ignoreThese.Add(attachment);
3496 }
3497 }
3498
3499 foreach (SceneObjectGroup attachment in ignoreThese)
3500 {
3501 attachments.Remove(attachment);
3502 }
3503 ignoreThese.Clear();
3504
3505 // if filtering by same object creator removed all
3506 // attachments to check, exit now
3507 if (attachments.Count == 0)
3508 {
3509 return;
3510 }
3511 }
3512
3513 if ((options & ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0)
3514 {
3515 foreach (SceneObjectGroup attachment in attachments)
3516 {
3517 if (attachment.RootPart.CreatorID != m_item.CreatorID)
3518 {
3519 ignoreThese.Add(attachment);
3520 }
3521 }
3522
3523 foreach (SceneObjectGroup attachment in ignoreThese)
3524 {
3525 attachments.Remove(attachment);
3526 }
3527 ignoreThese.Clear();
3528
3529 // if filtering by object creator must match originating
3530 // script creator removed all attachments to check,
3531 // exit now
3532 if (attachments.Count == 0)
3533 {
3534 return;
3535 }
3536 }
3537
3538 foreach (SceneObjectGroup attachment in attachments)
3539 {
3540 MessageObject(attachment.RootPart.UUID, message);
3541 }
3542 }
3543 }
3544
3545 #endregion
3546
3346 /// <summary> 3547 /// <summary>
3347 /// Checks if thing is a UUID. 3548 /// Checks if thing is a UUID.
3348 /// </summary> 3549 /// </summary>
@@ -3392,5 +3593,103 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3392 3593
3393 return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); 3594 return new LSL_Key(m_host.ParentGroup.FromPartID.ToString());
3394 } 3595 }
3596
3597 /// <summary>
3598 /// Sets the response type for an HTTP request/response
3599 /// </summary>
3600 /// <returns></returns>
3601 public void osSetContentType(LSL_Key id, string type)
3602 {
3603 CheckThreatLevel(ThreatLevel.High, "osSetContentType");
3604
3605 if (m_UrlModule != null)
3606 m_UrlModule.HttpContentType(new UUID(id),type);
3607 }
3608
3609 /// Shout an error if the object owner did not grant the script the specified permissions.
3610 /// </summary>
3611 /// <param name="perms"></param>
3612 /// <returns>boolean indicating whether an error was shouted.</returns>
3613 protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix)
3614 {
3615 m_host.AddScriptLPS(1);
3616 bool fail = false;
3617 if (m_item.PermsGranter != m_host.OwnerID)
3618 {
3619 fail = true;
3620 OSSLShoutError(string.Format("{0}. Permissions not granted to owner.", errorPrefix));
3621 }
3622 else if ((m_item.PermsMask & perms) == 0)
3623 {
3624 fail = true;
3625 OSSLShoutError(string.Format("{0}. Permissions not granted.", errorPrefix));
3626 }
3627
3628 return fail;
3629 }
3630
3631 protected void DropAttachment(bool checkPerms)
3632 {
3633 if (checkPerms && ShoutErrorOnLackingOwnerPerms(ScriptBaseClass.PERMISSION_ATTACH, "Cannot drop attachment"))
3634 {
3635 return;
3636 }
3637
3638 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
3639 ScenePresence sp = attachmentsModule == null ? null : m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.OwnerID);
3640
3641 if (attachmentsModule != null && sp != null)
3642 {
3643 attachmentsModule.DetachSingleAttachmentToGround(sp, m_host.ParentGroup.LocalId);
3644 }
3645 }
3646
3647 protected void DropAttachmentAt(bool checkPerms, LSL_Vector pos, LSL_Rotation rot)
3648 {
3649 if (checkPerms && ShoutErrorOnLackingOwnerPerms(ScriptBaseClass.PERMISSION_ATTACH, "Cannot drop attachment"))
3650 {
3651 return;
3652 }
3653
3654 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
3655 ScenePresence sp = attachmentsModule == null ? null : m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.OwnerID);
3656
3657 if (attachmentsModule != null && sp != null)
3658 {
3659 attachmentsModule.DetachSingleAttachmentToGround(sp, m_host.ParentGroup.LocalId, pos, rot);
3660 }
3661 }
3662
3663 public void osDropAttachment()
3664 {
3665 CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment");
3666 m_host.AddScriptLPS(1);
3667
3668 DropAttachment(true);
3669 }
3670
3671 public void osForceDropAttachment()
3672 {
3673 CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment");
3674 m_host.AddScriptLPS(1);
3675
3676 DropAttachment(false);
3677 }
3678
3679 public void osDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot)
3680 {
3681 CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachmentAt");
3682 m_host.AddScriptLPS(1);
3683
3684 DropAttachmentAt(true, pos, rot);
3685 }
3686
3687 public void osForceDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot)
3688 {
3689 CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt");
3690 m_host.AddScriptLPS(1);
3691
3692 DropAttachmentAt(false, pos, rot);
3693 }
3395 } 3694 }
3396} 3695}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 678f9d5..4dd795d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -352,7 +352,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
352 q = avatar.Rotation; 352 q = avatar.Rotation;
353 } 353 }
354 354
355 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 355 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
356 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); 356 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
357 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); 357 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
358 358
@@ -429,9 +429,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
429 try 429 try
430 { 430 {
431 Vector3 diff = toRegionPos - fromRegionPos; 431 Vector3 diff = toRegionPos - fromRegionPos;
432 LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z); 432 double dot = LSL_Types.Vector3.Dot(forward_dir, diff);
433 double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir); 433 double mag_obj = LSL_Types.Vector3.Mag(diff);
434 double mag_obj = LSL_Types.Vector3.Mag(obj_dir);
435 ang_obj = Math.Acos(dot / (mag_fwd * mag_obj)); 434 ang_obj = Math.Acos(dot / (mag_fwd * mag_obj));
436 } 435 }
437 catch 436 catch
@@ -483,7 +482,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
483 q = avatar.Rotation; 482 q = avatar.Rotation;
484 } 483 }
485 484
486 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 485 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
487 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); 486 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
488 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); 487 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
489 bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0); 488 bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0);
@@ -564,8 +563,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
564 double ang_obj = 0; 563 double ang_obj = 0;
565 try 564 try
566 { 565 {
567 Vector3 diff = toRegionPos - fromRegionPos; 566 LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(
568 LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z); 567 toRegionPos - fromRegionPos);
569 double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir); 568 double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir);
570 double mag_obj = LSL_Types.Vector3.Mag(obj_dir); 569 double mag_obj = LSL_Types.Vector3.Mag(obj_dir);
571 ang_obj = Math.Acos(dot / (mag_fwd * mag_obj)); 570 ang_obj = Math.Acos(dot / (mag_fwd * mag_obj));
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
index af35258..05c20f9 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
@@ -429,8 +429,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
429 LSL_Integer llGetLinkNumberOfSides(LSL_Integer link); 429 LSL_Integer llGetLinkNumberOfSides(LSL_Integer link);
430 void llSetPhysicsMaterial(int material_bits, float material_gravity_modifier, float material_restitution, float material_friction, float material_density); 430 void llSetPhysicsMaterial(int material_bits, float material_gravity_modifier, float material_restitution, float material_friction, float material_density);
431 431
432 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 432 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc);
433 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
434 void llSetKeyframedMotion(LSL_List frames, LSL_List options); 433 void llSetKeyframedMotion(LSL_List frames, LSL_List options);
434 LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
435 } 435 }
436} 436}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 8c34ed3..b1fbed5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -40,16 +40,75 @@ using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
40 40
41namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces 41namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
42{ 42{
43 /// <summary>
44 /// To permit region owners to enable the extended scripting functionality
45 /// of OSSL, without allowing malicious scripts to access potentially
46 /// troublesome functions, each OSSL function is assigned a threat level,
47 /// and access to the functions is granted or denied based on a default
48 /// threshold set in OpenSim.ini (which can be overridden for individual
49 /// functions on a case-by-case basis)
50 /// </summary>
43 public enum ThreatLevel 51 public enum ThreatLevel
44 { 52 {
53 // Not documented, presumably means permanently disabled ?
45 NoAccess = -1, 54 NoAccess = -1,
55
56 /// <summary>
57 /// Function is no threat at all. It doesn't constitute a threat to
58 /// either users or the system and has no known side effects.
59 /// </summary>
46 None = 0, 60 None = 0,
61
62 /// <summary>
63 /// Abuse of this command can cause a nuisance to the region operator,
64 /// such as log message spew.
65 /// </summary>
47 Nuisance = 1, 66 Nuisance = 1,
67
68 /// <summary>
69 /// Extreme levels of abuse of this function can cause impaired
70 /// functioning of the region, or very gullible users can be tricked
71 /// into experiencing harmless effects.
72 /// </summary>
48 VeryLow = 2, 73 VeryLow = 2,
74
75 /// <summary>
76 /// Intentional abuse can cause crashes or malfunction under certain
77 /// circumstances, which can be easily rectified; or certain users can
78 /// be tricked into certain situations in an avoidable manner.
79 /// </summary>
49 Low = 3, 80 Low = 3,
81
82 /// <summary>
83 /// Intentional abuse can cause denial of service and crashes with
84 /// potential of data or state loss; or trusting users can be tricked
85 /// into embarrassing or uncomfortable situations.
86 /// </summary>
50 Moderate = 4, 87 Moderate = 4,
88
89 /// <summary>
90 /// Casual abuse can cause impaired functionality or temporary denial
91 /// of service conditions. Intentional abuse can easily cause crashes
92 /// with potential data loss, or can be used to trick experienced and
93 /// cautious users into unwanted situations, or changes global data
94 /// permanently and without undo ability.
95 /// </summary>
51 High = 5, 96 High = 5,
97
98 /// <summary>
99 /// Even normal use may, depending on the number of instances, or
100 /// frequency of use, result in severe service impairment or crash
101 /// with loss of data, or can be used to cause unwanted or harmful
102 /// effects on users without giving the user a means to avoid it.
103 /// </summary>
52 VeryHigh = 6, 104 VeryHigh = 6,
105
106 /// <summary>
107 /// Even casual use is a danger to region stability, or function allows
108 /// console or OS command execution, or function allows taking money
109 /// without consent, or allows deletion or modification of user data,
110 /// or allows the compromise of sensitive data by design.
111 /// </summary>
53 Severe = 7 112 Severe = 7
54 }; 113 };
55 114
@@ -98,7 +157,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
98 void osAvatarPlayAnimation(string avatar, string animation); 157 void osAvatarPlayAnimation(string avatar, string animation);
99 void osAvatarStopAnimation(string avatar, string animation); 158 void osAvatarStopAnimation(string avatar, string animation);
100 159
101 // Attachment commands 160 #region Attachment commands
102 161
103 /// <summary> 162 /// <summary>
104 /// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH 163 /// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
@@ -133,6 +192,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
133 /// <remarks>Nothing happens if the object is not attached.</remarks> 192 /// <remarks>Nothing happens if the object is not attached.</remarks>
134 void osForceDetachFromAvatar(); 193 void osForceDetachFromAvatar();
135 194
195 /// <summary>
196 /// Returns a strided list of the specified attachment points and the number of attachments on those points.
197 /// </summary>
198 /// <param name="avatar">avatar UUID</param>
199 /// <param name="attachmentPoints">list of ATTACH_* constants</param>
200 /// <returns></returns>
201 LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints);
202
203 /// <summary>
204 /// Sends a specified message to the specified avatar's attachments on
205 /// the specified attachment points.
206 /// </summary>
207 /// <remarks>
208 /// Behaves as osMessageObject(), without the sending script needing to know the attachment keys in advance.
209 /// </remarks>
210 /// <param name="avatar">avatar UUID</param>
211 /// <param name="message">message string</param>
212 /// <param name="attachmentPoints">list of ATTACH_* constants, or -1 for all attachments. If -1 is specified and OS_ATTACH_MSG_INVERT_POINTS is present in flags, no action is taken.</param>
213 /// <param name="flags">flags further constraining the attachments to deliver the message to.</param>
214 void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int flags);
215
216 #endregion
217
136 //texture draw functions 218 //texture draw functions
137 string osMovePen(string drawList, int x, int y); 219 string osMovePen(string drawList, int x, int y);
138 string osDrawLine(string drawList, int startX, int startY, int endX, int endY); 220 string osDrawLine(string drawList, int startX, int startY, int endX, int endY);
@@ -258,6 +340,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
258 int osGetSimulatorMemory(); 340 int osGetSimulatorMemory();
259 void osKickAvatar(string FirstName,string SurName,string alert); 341 void osKickAvatar(string FirstName,string SurName,string alert);
260 void osSetSpeed(string UUID, LSL_Float SpeedModifier); 342 void osSetSpeed(string UUID, LSL_Float SpeedModifier);
343 LSL_Float osGetHealth(string avatar);
261 void osCauseHealing(string avatar, double healing); 344 void osCauseHealing(string avatar, double healing);
262 void osCauseDamage(string avatar, double damage); 345 void osCauseDamage(string avatar, double damage);
263 LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules); 346 LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules);
@@ -305,5 +388,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
305 /// </summary> 388 /// </summary>
306 /// <returns>Rezzing object key or NULL_KEY if rezzed by agent or otherwise unknown.</returns> 389 /// <returns>Rezzing object key or NULL_KEY if rezzed by agent or otherwise unknown.</returns>
307 LSL_Key osGetRezzingObject(); 390 LSL_Key osGetRezzingObject();
391
392 /// <summary>
393 /// Sets the response type for an HTTP request/response
394 /// </summary>
395 /// <returns></returns>
396 void osSetContentType(LSL_Key id, string type);
397
398 /// <summary>
399 /// Attempts to drop an attachment to the ground
400 /// </summary>
401 void osDropAttachment();
402
403 /// <summary>
404 /// Attempts to drop an attachment to the ground while bypassing the script permissions
405 /// </summary>
406 void osForceDropAttachment();
407
408 /// <summary>
409 /// Attempts to drop an attachment at the specified coordinates.
410 /// </summary>
411 /// <param name="pos"></param>
412 /// <param name="rot"></param>
413 void osDropAttachmentAt(vector pos, rotation rot);
414
415 /// <summary>
416 /// Attempts to drop an attachment at the specified coordinates while bypassing the script permissions
417 /// </summary>
418 /// <param name="pos"></param>
419 /// <param name="rot"></param>
420 void osForceDropAttachmentAt(vector pos, rotation rot);
308 } 421 }
309} 422}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index f989cc6..c788407 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -237,6 +237,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
237 public const int ATTACH_HUD_BOTTOM = 37; 237 public const int ATTACH_HUD_BOTTOM = 37;
238 public const int ATTACH_HUD_BOTTOM_RIGHT = 38; 238 public const int ATTACH_HUD_BOTTOM_RIGHT = 38;
239 239
240 #region osMessageAttachments constants
241
242 /// <summary>
243 /// Instructs osMessageAttachements to send the message to attachments
244 /// on every point.
245 /// </summary>
246 /// <remarks>
247 /// One might expect this to be named OS_ATTACH_ALL, but then one might
248 /// also expect functions designed to attach or detach or get
249 /// attachments to work with it too. Attaching a no-copy item to
250 /// many attachments could be dangerous.
251 /// when combined with OS_ATTACH_MSG_INVERT_POINTS, will prevent the
252 /// message from being sent.
253 /// if combined with OS_ATTACH_MSG_OBJECT_CREATOR or
254 /// OS_ATTACH_MSG_SCRIPT_CREATOR, could result in no message being
255 /// sent- this is expected behaviour.
256 /// </remarks>
257 public const int OS_ATTACH_MSG_ALL = -65535;
258
259 /// <summary>
260 /// Instructs osMessageAttachements to invert how the attachment points
261 /// list should be treated (e.g. go from inclusive operation to
262 /// exclusive operation).
263 /// </summary>
264 /// <remarks>
265 /// This might be used if you want to deliver a message to one set of
266 /// attachments and a different message to everything else. With
267 /// this flag, you only need to build one explicit list for both calls.
268 /// </remarks>
269 public const int OS_ATTACH_MSG_INVERT_POINTS = 1;
270
271 /// <summary>
272 /// Instructs osMessageAttachments to only send the message to
273 /// attachments with a CreatorID that matches the host object CreatorID
274 /// </summary>
275 /// <remarks>
276 /// This would be used if distributed in an object vendor/updater server.
277 /// </remarks>
278 public const int OS_ATTACH_MSG_OBJECT_CREATOR = 2;
279
280 /// <summary>
281 /// Instructs osMessageAttachments to only send the message to
282 /// attachments with a CreatorID that matches the sending script CreatorID
283 /// </summary>
284 /// <remarks>
285 /// This might be used if the script is distributed independently of a
286 /// containing object.
287 /// </remarks>
288 public const int OS_ATTACH_MSG_SCRIPT_CREATOR = 4;
289
290 #endregion
291
240 public const int LAND_LEVEL = 0; 292 public const int LAND_LEVEL = 0;
241 public const int LAND_RAISE = 1; 293 public const int LAND_RAISE = 1;
242 public const int LAND_LOWER = 2; 294 public const int LAND_LOWER = 2;
@@ -329,6 +381,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
329 public const int PRIM_OMEGA = 32; 381 public const int PRIM_OMEGA = 32;
330 public const int PRIM_POS_LOCAL = 33; 382 public const int PRIM_POS_LOCAL = 33;
331 public const int PRIM_LINK_TARGET = 34; 383 public const int PRIM_LINK_TARGET = 34;
384 public const int PRIM_SLICE = 35;
332 public const int PRIM_TEXGEN_DEFAULT = 0; 385 public const int PRIM_TEXGEN_DEFAULT = 0;
333 public const int PRIM_TEXGEN_PLANAR = 1; 386 public const int PRIM_TEXGEN_PLANAR = 1;
334 387
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 94405d2..dee1b28 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -289,7 +289,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
289 m_OSSL_Functions.osAvatarStopAnimation(avatar, animation); 289 m_OSSL_Functions.osAvatarStopAnimation(avatar, animation);
290 } 290 }
291 291
292 // Avatar functions 292 #region Attachment commands
293 293
294 public void osForceAttachToAvatar(int attachmentPoint) 294 public void osForceAttachToAvatar(int attachmentPoint)
295 { 295 {
@@ -311,6 +311,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
311 m_OSSL_Functions.osForceDetachFromAvatar(); 311 m_OSSL_Functions.osForceDetachFromAvatar();
312 } 312 }
313 313
314 public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints)
315 {
316 return m_OSSL_Functions.osGetNumberOfAttachments(avatar, attachmentPoints);
317 }
318
319 public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int flags)
320 {
321 m_OSSL_Functions.osMessageAttachments(avatar, message, attachmentPoints, flags);
322 }
323
324 #endregion
325
314 // Texture Draw functions 326 // Texture Draw functions
315 327
316 public string osMovePen(string drawList, int x, int y) 328 public string osMovePen(string drawList, int x, int y)
@@ -865,7 +877,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
865 { 877 {
866 m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier); 878 m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier);
867 } 879 }
868 880
881 public LSL_Float osGetHealth(string avatar)
882 {
883 return m_OSSL_Functions.osGetHealth(avatar);
884 }
885
869 public void osCauseDamage(string avatar, double damage) 886 public void osCauseDamage(string avatar, double damage)
870 { 887 {
871 m_OSSL_Functions.osCauseDamage(avatar, damage); 888 m_OSSL_Functions.osCauseDamage(avatar, damage);
@@ -950,5 +967,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
950 { 967 {
951 return m_OSSL_Functions.osGetRezzingObject(); 968 return m_OSSL_Functions.osGetRezzingObject();
952 } 969 }
970
971 public void osSetContentType(LSL_Key id, string type)
972 {
973 m_OSSL_Functions.osSetContentType(id,type);
974 }
975
976 public void osDropAttachment()
977 {
978 m_OSSL_Functions.osDropAttachment();
979 }
980
981 public void osForceDropAttachment()
982 {
983 m_OSSL_Functions.osForceDropAttachment();
984 }
985
986 public void osDropAttachmentAt(vector pos, rotation rot)
987 {
988 m_OSSL_Functions.osDropAttachmentAt(pos, rot);
989 }
990
991 public void osForceDropAttachmentAt(vector pos, rotation rot)
992 {
993 m_OSSL_Functions.osForceDropAttachmentAt(pos, rot);
994 }
953 } 995 }
954} 996}
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
index 17a0d69..03be2ab 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs
@@ -546,6 +546,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
546 "OpenSim.Region.ScriptEngine.Shared.dll")); 546 "OpenSim.Region.ScriptEngine.Shared.dll"));
547 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, 547 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
548 "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); 548 "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll"));
549 parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
550 "OpenMetaverseTypes.dll"));
549 551
550 if (lang == enumCompileType.yp) 552 if (lang == enumCompileType.yp)
551 { 553 {
diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
index 9e5fb24..22804f5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
@@ -164,11 +164,11 @@ namespace OpenSim.Region.ScriptEngine.Shared
164 else 164 else
165 { 165 {
166 // Set the values from the touch data provided by the client 166 // Set the values from the touch data provided by the client
167 touchST = new LSL_Types.Vector3(value.STCoord.X, value.STCoord.Y, value.STCoord.Z); 167 touchST = new LSL_Types.Vector3(value.STCoord);
168 touchUV = new LSL_Types.Vector3(value.UVCoord.X, value.UVCoord.Y, value.UVCoord.Z); 168 touchUV = new LSL_Types.Vector3(value.UVCoord);
169 touchNormal = new LSL_Types.Vector3(value.Normal.X, value.Normal.Y, value.Normal.Z); 169 touchNormal = new LSL_Types.Vector3(value.Normal);
170 touchBinormal = new LSL_Types.Vector3(value.Binormal.X, value.Binormal.Y, value.Binormal.Z); 170 touchBinormal = new LSL_Types.Vector3(value.Binormal);
171 touchPos = new LSL_Types.Vector3(value.Position.X, value.Position.Y, value.Position.Z); 171 touchPos = new LSL_Types.Vector3(value.Position);
172 touchFace = value.FaceIndex; 172 touchFace = value.FaceIndex;
173 } 173 }
174 } 174 }
@@ -189,19 +189,13 @@ namespace OpenSim.Region.ScriptEngine.Shared
189 Country = account.UserCountry; 189 Country = account.UserCountry;
190 190
191 Owner = Key; 191 Owner = Key;
192 Position = new LSL_Types.Vector3( 192 Position = new LSL_Types.Vector3(presence.AbsolutePosition);
193 presence.AbsolutePosition.X,
194 presence.AbsolutePosition.Y,
195 presence.AbsolutePosition.Z);
196 Rotation = new LSL_Types.Quaternion( 193 Rotation = new LSL_Types.Quaternion(
197 presence.Rotation.X, 194 presence.Rotation.X,
198 presence.Rotation.Y, 195 presence.Rotation.Y,
199 presence.Rotation.Z, 196 presence.Rotation.Z,
200 presence.Rotation.W); 197 presence.Rotation.W);
201 Velocity = new LSL_Types.Vector3( 198 Velocity = new LSL_Types.Vector3(presence.Velocity);
202 presence.Velocity.X,
203 presence.Velocity.Y,
204 presence.Velocity.Z);
205 199
206 Type = 0x01; // Avatar 200 Type = 0x01; // Avatar
207 if (presence.PresenceType == PresenceType.Npc) 201 if (presence.PresenceType == PresenceType.Npc)
@@ -254,16 +248,12 @@ namespace OpenSim.Region.ScriptEngine.Shared
254 } 248 }
255 } 249 }
256 250
257 Position = new LSL_Types.Vector3(part.AbsolutePosition.X, 251 Position = new LSL_Types.Vector3(part.AbsolutePosition);
258 part.AbsolutePosition.Y,
259 part.AbsolutePosition.Z);
260 252
261 Quaternion wr = part.ParentGroup.GroupRotation; 253 Quaternion wr = part.ParentGroup.GroupRotation;
262 Rotation = new LSL_Types.Quaternion(wr.X, wr.Y, wr.Z, wr.W); 254 Rotation = new LSL_Types.Quaternion(wr.X, wr.Y, wr.Z, wr.W);
263 255
264 Velocity = new LSL_Types.Vector3(part.Velocity.X, 256 Velocity = new LSL_Types.Vector3(part.Velocity);
265 part.Velocity.Y,
266 part.Velocity.Z);
267 } 257 }
268 } 258 }
269 259
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index 8adf4c5..c9c4753 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -31,6 +31,11 @@ using System.Globalization;
31using System.Text.RegularExpressions; 31using System.Text.RegularExpressions;
32using OpenSim.Framework; 32using OpenSim.Framework;
33 33
34using OpenMetaverse;
35using OMV_Vector3 = OpenMetaverse.Vector3;
36using OMV_Vector3d = OpenMetaverse.Vector3d;
37using OMV_Quaternion = OpenMetaverse.Quaternion;
38
34namespace OpenSim.Region.ScriptEngine.Shared 39namespace OpenSim.Region.ScriptEngine.Shared
35{ 40{
36 [Serializable] 41 [Serializable]
@@ -54,6 +59,20 @@ namespace OpenSim.Region.ScriptEngine.Shared
54 z = (float)vector.z; 59 z = (float)vector.z;
55 } 60 }
56 61
62 public Vector3(OMV_Vector3 vector)
63 {
64 x = vector.X;
65 y = vector.Y;
66 z = vector.Z;
67 }
68
69 public Vector3(OMV_Vector3d vector)
70 {
71 x = vector.X;
72 y = vector.Y;
73 z = vector.Z;
74 }
75
57 public Vector3(double X, double Y, double Z) 76 public Vector3(double X, double Y, double Z)
58 { 77 {
59 x = X; 78 x = X;
@@ -109,6 +128,26 @@ namespace OpenSim.Region.ScriptEngine.Shared
109 return new list(new object[] { vec }); 128 return new list(new object[] { vec });
110 } 129 }
111 130
131 public static implicit operator OMV_Vector3(Vector3 vec)
132 {
133 return new OMV_Vector3((float)vec.x, (float)vec.y, (float)vec.z);
134 }
135
136 public static implicit operator Vector3(OMV_Vector3 vec)
137 {
138 return new Vector3(vec);
139 }
140
141 public static implicit operator OMV_Vector3d(Vector3 vec)
142 {
143 return new OMV_Vector3d(vec.x, vec.y, vec.z);
144 }
145
146 public static implicit operator Vector3(OMV_Vector3d vec)
147 {
148 return new Vector3(vec);
149 }
150
112 public static bool operator ==(Vector3 lhs, Vector3 rhs) 151 public static bool operator ==(Vector3 lhs, Vector3 rhs)
113 { 152 {
114 return (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z); 153 return (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z);
@@ -322,6 +361,14 @@ namespace OpenSim.Region.ScriptEngine.Shared
322 s = 1; 361 s = 1;
323 } 362 }
324 363
364 public Quaternion(OMV_Quaternion rot)
365 {
366 x = rot.X;
367 y = rot.Y;
368 z = rot.Z;
369 s = rot.W;
370 }
371
325 #endregion 372 #endregion
326 373
327 #region Overriders 374 #region Overriders
@@ -368,6 +415,21 @@ namespace OpenSim.Region.ScriptEngine.Shared
368 return new list(new object[] { r }); 415 return new list(new object[] { r });
369 } 416 }
370 417
418 public static implicit operator OMV_Quaternion(Quaternion rot)
419 {
420 // LSL quaternions can normalize to 0, normal Quaternions can't.
421 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
422 rot.z = 1; // ZERO_ROTATION = 0,0,0,1
423 OMV_Quaternion omvrot = new OMV_Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
424 omvrot.Normalize();
425 return omvrot;
426 }
427
428 public static implicit operator Quaternion(OMV_Quaternion rot)
429 {
430 return new Quaternion(rot);
431 }
432
371 public static bool operator ==(Quaternion lhs, Quaternion rhs) 433 public static bool operator ==(Quaternion lhs, Quaternion rhs)
372 { 434 {
373 // Return true if the fields match: 435 // Return true if the fields match:
@@ -562,12 +624,23 @@ namespace OpenSim.Region.ScriptEngine.Shared
562 else if (m_data[itemIndex] is LSL_Types.LSLString) 624 else if (m_data[itemIndex] is LSL_Types.LSLString)
563 return new LSLInteger(m_data[itemIndex].ToString()); 625 return new LSLInteger(m_data[itemIndex].ToString());
564 else 626 else
565 throw new InvalidCastException(); 627 throw new InvalidCastException(string.Format(
628 "{0} expected but {1} given",
629 typeof(LSL_Types.LSLInteger).Name,
630 m_data[itemIndex] != null ?
631 m_data[itemIndex].GetType().Name : "null"));
566 } 632 }
567 633
568 public LSL_Types.Vector3 GetVector3Item(int itemIndex) 634 public LSL_Types.Vector3 GetVector3Item(int itemIndex)
569 { 635 {
570 return (LSL_Types.Vector3)m_data[itemIndex]; 636 if(m_data[itemIndex] is LSL_Types.Vector3)
637 return (LSL_Types.Vector3)m_data[itemIndex];
638 else
639 throw new InvalidCastException(string.Format(
640 "{0} expected but {1} given",
641 typeof(LSL_Types.Vector3).Name,
642 m_data[itemIndex] != null ?
643 m_data[itemIndex].GetType().Name : "null"));
571 } 644 }
572 645
573 public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) 646 public LSL_Types.Quaternion GetQuaternionItem(int itemIndex)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
new file mode 100644
index 0000000..dd23be8
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
@@ -0,0 +1,134 @@
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 NUnit.Framework;
31using OpenSim.Framework;
32using OpenSim.Tests.Common;
33using OpenSim.Region.ScriptEngine.Shared;
34using OpenSim.Region.Framework.Scenes;
35using Nini.Config;
36using OpenSim.Region.ScriptEngine.Shared.Api;
37using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
38using OpenMetaverse;
39using OpenSim.Tests.Common.Mock;
40
41using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
42using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
43using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
44using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
45
46namespace OpenSim.Region.ScriptEngine.Shared.Tests
47{
48 [TestFixture]
49 public class LSL_ApiListTests
50 {
51 private LSL_Api m_lslApi;
52
53 [SetUp]
54 public void SetUp()
55 {
56 IConfigSource initConfigSource = new IniConfigSource();
57 IConfig config = initConfigSource.AddConfig("XEngine");
58 config.Set("Enabled", "true");
59
60 Scene scene = new SceneHelpers().SetupScene();
61 SceneObjectPart part = SceneHelpers.AddSceneObject(scene).RootPart;
62
63 XEngine.XEngine engine = new XEngine.XEngine();
64 engine.Initialise(initConfigSource);
65 engine.AddRegion(scene);
66
67 m_lslApi = new LSL_Api();
68 m_lslApi.Initialize(engine, part, null);
69 }
70
71 [Test]
72 public void TestllListFindList()
73 {
74 TestHelpers.InMethod();
75
76 LSL_List src = new LSL_List(new LSL_Integer(1), new LSL_Integer(2), new LSL_Integer(3));
77
78 {
79 // Test for a single item that should be found
80 int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4)));
81 Assert.That(result, Is.EqualTo(-1));
82 }
83
84 {
85 // Test for a single item that should be found
86 int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2)));
87 Assert.That(result, Is.EqualTo(1));
88 }
89
90 {
91 // Test for a constant that should be found
92 int result = m_lslApi.llListFindList(src, new LSL_List(ScriptBaseClass.AGENT));
93 Assert.That(result, Is.EqualTo(0));
94 }
95
96 {
97 // Test for a list that should be found
98 int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3)));
99 Assert.That(result, Is.EqualTo(1));
100 }
101
102 {
103 // Test for a single item not in the list
104 int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4)));
105 Assert.That(result, Is.EqualTo(-1));
106 }
107
108 {
109 // Test for something that should not be cast
110 int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_String("4")));
111 Assert.That(result, Is.EqualTo(-1));
112 }
113
114 {
115 // Test for a list not in the list
116 int result
117 = m_lslApi.llListFindList(
118 src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3), new LSL_Integer(4)));
119 Assert.That(result, Is.EqualTo(-1));
120 }
121
122 {
123 LSL_List srcWithConstants
124 = new LSL_List(new LSL_Integer(3), ScriptBaseClass.AGENT, ScriptBaseClass.OS_NPC_LAND_AT_TARGET);
125
126 // Test for constants that appears in the source list that should be found
127 int result
128 = m_lslApi.llListFindList(srcWithConstants, new LSL_List(new LSL_Integer(1), new LSL_Integer(2)));
129
130 Assert.That(result, Is.EqualTo(1));
131 }
132 }
133 }
134 } \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
index 5c4174e..9405075 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
@@ -96,9 +96,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
96 if (part == null) 96 if (part == null)
97 return; 97 return;
98 98
99 if ((part.ScriptEvents & scriptEvents.money) == 0)
100 part = part.ParentGroup.RootPart;
101
99 m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount); 102 m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount);
100 103
101 part = part.ParentGroup.RootPart; 104// part = part.ParentGroup.RootPart;
102 money(part.LocalId, agentID, amount); 105 money(part.LocalId, agentID, amount);
103 } 106 }
104 107
@@ -152,9 +155,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
152 det[0] = new DetectParams(); 155 det[0] = new DetectParams();
153 det[0].Key = remoteClient.AgentId; 156 det[0].Key = remoteClient.AgentId;
154 det[0].Populate(myScriptEngine.World); 157 det[0].Populate(myScriptEngine.World);
155 det[0].OffsetPos = new LSL_Types.Vector3(offsetPos.X, 158 det[0].OffsetPos = offsetPos;
156 offsetPos.Y,
157 offsetPos.Z);
158 159
159 if (originalID == 0) 160 if (originalID == 0)
160 { 161 {
@@ -298,9 +299,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
298 foreach (DetectedObject detobj in col.Colliders) 299 foreach (DetectedObject detobj in col.Colliders)
299 { 300 {
300 DetectParams d = new DetectParams(); 301 DetectParams d = new DetectParams();
301 d.Position = new LSL_Types.Vector3(detobj.posVector.X, 302 d.Position = detobj.posVector;
302 detobj.posVector.Y,
303 detobj.posVector.Z);
304 d.Populate(myScriptEngine.World); 303 d.Populate(myScriptEngine.World);
305 det.Add(d); 304 det.Add(d);
306 myScriptEngine.PostObjectEvent(localID, new EventParams( 305 myScriptEngine.PostObjectEvent(localID, new EventParams(
@@ -318,9 +317,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
318 foreach (DetectedObject detobj in col.Colliders) 317 foreach (DetectedObject detobj in col.Colliders)
319 { 318 {
320 DetectParams d = new DetectParams(); 319 DetectParams d = new DetectParams();
321 d.Position = new LSL_Types.Vector3(detobj.posVector.X, 320 d.Position = detobj.posVector;
322 detobj.posVector.Y,
323 detobj.posVector.Z);
324 d.Populate(myScriptEngine.World); 321 d.Populate(myScriptEngine.World);
325 det.Add(d); 322 det.Add(d);
326 myScriptEngine.PostObjectEvent(localID, new EventParams( 323 myScriptEngine.PostObjectEvent(localID, new EventParams(
@@ -337,9 +334,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
337 foreach (DetectedObject detobj in col.Colliders) 334 foreach (DetectedObject detobj in col.Colliders)
338 { 335 {
339 DetectParams d = new DetectParams(); 336 DetectParams d = new DetectParams();
340 d.Position = new LSL_Types.Vector3(detobj.posVector.X, 337 d.Position = detobj.posVector;
341 detobj.posVector.Y,
342 detobj.posVector.Z);
343 d.Populate(myScriptEngine.World); 338 d.Populate(myScriptEngine.World);
344 det.Add(d); 339 det.Add(d);
345 myScriptEngine.PostObjectEvent(localID, new EventParams( 340 myScriptEngine.PostObjectEvent(localID, new EventParams(
@@ -381,8 +376,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
381 myScriptEngine.PostObjectEvent(localID, new EventParams( 376 myScriptEngine.PostObjectEvent(localID, new EventParams(
382 "at_target", new object[] { 377 "at_target", new object[] {
383 new LSL_Types.LSLInteger(handle), 378 new LSL_Types.LSLInteger(handle),
384 new LSL_Types.Vector3(targetpos.X,targetpos.Y,targetpos.Z), 379 new LSL_Types.Vector3(targetpos),
385 new LSL_Types.Vector3(atpos.X,atpos.Y,atpos.Z) }, 380 new LSL_Types.Vector3(atpos) },
386 new DetectParams[0])); 381 new DetectParams[0]));
387 } 382 }
388 383
@@ -399,8 +394,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
399 myScriptEngine.PostObjectEvent(localID, new EventParams( 394 myScriptEngine.PostObjectEvent(localID, new EventParams(
400 "at_rot_target", new object[] { 395 "at_rot_target", new object[] {
401 new LSL_Types.LSLInteger(handle), 396 new LSL_Types.LSLInteger(handle),
402 new LSL_Types.Quaternion(targetrot.X,targetrot.Y,targetrot.Z,targetrot.W), 397 new LSL_Types.Quaternion(targetrot),
403 new LSL_Types.Quaternion(atrot.X,atrot.Y,atrot.Z,atrot.W) }, 398 new LSL_Types.Quaternion(atrot) },
404 new DetectParams[0])); 399 new DetectParams[0]));
405 } 400 }
406 401
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index f6cb7df..9f05666 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -656,7 +656,19 @@ namespace OpenSim.Region.ScriptEngine.XEngine
656 if (m_Assemblies.ContainsKey(instance.AssetID)) 656 if (m_Assemblies.ContainsKey(instance.AssetID))
657 { 657 {
658 string assembly = m_Assemblies[instance.AssetID]; 658 string assembly = m_Assemblies[instance.AssetID];
659 instance.SaveState(assembly); 659
660 try
661 {
662 instance.SaveState(assembly);
663 }
664 catch (Exception e)
665 {
666 m_log.Error(
667 string.Format(
668 "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
669 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
670 , e);
671 }
660 } 672 }
661 673
662 // Clear the event queue and abort the instance thread 674 // Clear the event queue and abort the instance thread
@@ -778,7 +790,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine
778 assembly = m_Assemblies[i.AssetID]; 790 assembly = m_Assemblies[i.AssetID];
779 791
780 792
781 i.SaveState(assembly); 793 try
794 {
795 i.SaveState(assembly);
796 }
797 catch (Exception e)
798 {
799 m_log.Error(
800 string.Format(
801 "[XEngine]: Failed to save state of script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
802 i.PrimName, i.ScriptName, i.ItemID, i.ObjectID, World.Name)
803 , e);
804 }
782 } 805 }
783 806
784 instances.Clear(); 807 instances.Clear();
@@ -971,6 +994,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
971 // This delay exists to stop mono problems where script compilation and startup would stop the sim 994 // This delay exists to stop mono problems where script compilation and startup would stop the sim
972 // working properly for the session. 995 // working properly for the session.
973 System.Threading.Thread.Sleep(m_StartDelay); 996 System.Threading.Thread.Sleep(m_StartDelay);
997
998 m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name);
974 } 999 }
975 1000
976 object[] o; 1001 object[] o;
@@ -986,13 +1011,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine
986 if (m_InitialStartup) 1011 if (m_InitialStartup)
987 if (scriptsStarted % 50 == 0) 1012 if (scriptsStarted % 50 == 0)
988 m_log.InfoFormat( 1013 m_log.InfoFormat(
989 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); 1014 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name);
990 } 1015 }
991 } 1016 }
992 1017
993 if (m_InitialStartup) 1018 if (m_InitialStartup)
994 m_log.InfoFormat( 1019 m_log.InfoFormat(
995 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); 1020 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name);
996 1021
997 // NOTE: Despite having a lockless queue, this lock is required 1022 // NOTE: Despite having a lockless queue, this lock is required
998 // to make sure there is never no compile thread while there 1023 // to make sure there is never no compile thread while there
@@ -1053,10 +1078,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1053 return false; 1078 return false;
1054 } 1079 }
1055 1080
1056 UUID assetID = item.AssetID; 1081 m_log.DebugFormat(
1082 "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1083 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1084 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1057 1085
1058 //m_log.DebugFormat("[XEngine] Compiling script {0} ({1} on object {2})", 1086 UUID assetID = item.AssetID;
1059 // item.Name, itemID.ToString(), part.ParentGroup.RootPart.Name);
1060 1087
1061 ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); 1088 ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID);
1062 1089
@@ -1235,10 +1262,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1235 item.Name, startParam, postOnRez, 1262 item.Name, startParam, postOnRez,
1236 stateSource, m_MaxScriptQueue); 1263 stateSource, m_MaxScriptQueue);
1237 1264
1238 m_log.DebugFormat( 1265// m_log.DebugFormat(
1239 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", 1266// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
1240 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, 1267// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
1241 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); 1268// part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1242 1269
1243 if (presence != null) 1270 if (presence != null)
1244 { 1271 {
@@ -1554,9 +1581,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1554 else if (p[i] is string) 1581 else if (p[i] is string)
1555 lsl_p[i] = new LSL_Types.LSLString((string)p[i]); 1582 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1556 else if (p[i] is Vector3) 1583 else if (p[i] is Vector3)
1557 lsl_p[i] = new LSL_Types.Vector3(((Vector3)p[i]).X, ((Vector3)p[i]).Y, ((Vector3)p[i]).Z); 1584 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1558 else if (p[i] is Quaternion) 1585 else if (p[i] is Quaternion)
1559 lsl_p[i] = new LSL_Types.Quaternion(((Quaternion)p[i]).X, ((Quaternion)p[i]).Y, ((Quaternion)p[i]).Z, ((Quaternion)p[i]).W); 1586 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1560 else if (p[i] is float) 1587 else if (p[i] is float)
1561 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]); 1588 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1562 else 1589 else
@@ -1580,9 +1607,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1580 else if (p[i] is string) 1607 else if (p[i] is string)
1581 lsl_p[i] = new LSL_Types.LSLString((string)p[i]); 1608 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1582 else if (p[i] is Vector3) 1609 else if (p[i] is Vector3)
1583 lsl_p[i] = new LSL_Types.Vector3(((Vector3)p[i]).X, ((Vector3)p[i]).Y, ((Vector3)p[i]).Z); 1610 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1584 else if (p[i] is Quaternion) 1611 else if (p[i] is Quaternion)
1585 lsl_p[i] = new LSL_Types.Quaternion(((Quaternion)p[i]).X, ((Quaternion)p[i]).Y, ((Quaternion)p[i]).Z, ((Quaternion)p[i]).W); 1612 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1586 else if (p[i] is float) 1613 else if (p[i] is float)
1587 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]); 1614 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1588 else 1615 else
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
index c11ea02..625eba4 100644
--- a/OpenSim/Region/UserStatistics/WebStatsModule.cs
+++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs
@@ -61,7 +61,7 @@ namespace OpenSim.Region.UserStatistics
61 /// <summary> 61 /// <summary>
62 /// User statistics sessions keyed by agent ID 62 /// User statistics sessions keyed by agent ID
63 /// </summary> 63 /// </summary>
64 private Dictionary<UUID, UserSessionID> m_sessions = new Dictionary<UUID, UserSessionID>(); 64 private Dictionary<UUID, UserSession> m_sessions = new Dictionary<UUID, UserSession>();
65 65
66 private List<Scene> m_scenes = new List<Scene>(); 66 private List<Scene> m_scenes = new List<Scene>();
67 private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>(); 67 private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>();
@@ -319,14 +319,18 @@ namespace OpenSim.Region.UserStatistics
319 319
320 private void OnMakeRootAgent(ScenePresence agent) 320 private void OnMakeRootAgent(ScenePresence agent)
321 { 321 {
322// m_log.DebugFormat(
323// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}",
324// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name);
325
322 lock (m_sessions) 326 lock (m_sessions)
323 { 327 {
324 UserSessionID uid; 328 UserSession uid;
325 329
326 if (!m_sessions.ContainsKey(agent.UUID)) 330 if (!m_sessions.ContainsKey(agent.UUID))
327 { 331 {
328 UserSessionData usd = UserSessionUtil.newUserSessionData(); 332 UserSessionData usd = UserSessionUtil.newUserSessionData();
329 uid = new UserSessionID(); 333 uid = new UserSession();
330 uid.name_f = agent.Firstname; 334 uid.name_f = agent.Firstname;
331 uid.name_l = agent.Lastname; 335 uid.name_l = agent.Lastname;
332 uid.session_data = usd; 336 uid.session_data = usd;
@@ -411,9 +415,9 @@ namespace OpenSim.Region.UserStatistics
411 return String.Empty; 415 return String.Empty;
412 } 416 }
413 417
414 private UserSessionID ParseViewerStats(string request, UUID agentID) 418 private UserSession ParseViewerStats(string request, UUID agentID)
415 { 419 {
416 UserSessionID uid = new UserSessionID(); 420 UserSession uid = new UserSession();
417 UserSessionData usd; 421 UserSessionData usd;
418 OSD message = OSDParser.DeserializeLLSDXml(request); 422 OSD message = OSDParser.DeserializeLLSDXml(request);
419 OSDMap mmap; 423 OSDMap mmap;
@@ -425,22 +429,25 @@ namespace OpenSim.Region.UserStatistics
425 if (!m_sessions.ContainsKey(agentID)) 429 if (!m_sessions.ContainsKey(agentID))
426 { 430 {
427 m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID); 431 m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID);
428 return new UserSessionID(); 432 return new UserSession();
429 } 433 }
434
430 uid = m_sessions[agentID]; 435 uid = m_sessions[agentID];
436
437// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID);
431 } 438 }
432 else 439 else
433 { 440 {
434 // parse through the beginning to locate the session 441 // parse through the beginning to locate the session
435 if (message.Type != OSDType.Map) 442 if (message.Type != OSDType.Map)
436 return new UserSessionID(); 443 return new UserSession();
437 444
438 mmap = (OSDMap)message; 445 mmap = (OSDMap)message;
439 { 446 {
440 UUID sessionID = mmap["session_id"].AsUUID(); 447 UUID sessionID = mmap["session_id"].AsUUID();
441 448
442 if (sessionID == UUID.Zero) 449 if (sessionID == UUID.Zero)
443 return new UserSessionID(); 450 return new UserSession();
444 451
445 452
446 // search through each session looking for the owner 453 // search through each session looking for the owner
@@ -459,7 +466,7 @@ namespace OpenSim.Region.UserStatistics
459 // can't find a session 466 // can't find a session
460 if (agentID == UUID.Zero) 467 if (agentID == UUID.Zero)
461 { 468 {
462 return new UserSessionID(); 469 return new UserSession();
463 } 470 }
464 } 471 }
465 } 472 }
@@ -468,12 +475,12 @@ namespace OpenSim.Region.UserStatistics
468 usd = uid.session_data; 475 usd = uid.session_data;
469 476
470 if (message.Type != OSDType.Map) 477 if (message.Type != OSDType.Map)
471 return new UserSessionID(); 478 return new UserSession();
472 479
473 mmap = (OSDMap)message; 480 mmap = (OSDMap)message;
474 { 481 {
475 if (mmap["agent"].Type != OSDType.Map) 482 if (mmap["agent"].Type != OSDType.Map)
476 return new UserSessionID(); 483 return new UserSession();
477 OSDMap agent_map = (OSDMap)mmap["agent"]; 484 OSDMap agent_map = (OSDMap)mmap["agent"];
478 usd.agent_id = agentID; 485 usd.agent_id = agentID;
479 usd.name_f = uid.name_f; 486 usd.name_f = uid.name_f;
@@ -493,17 +500,18 @@ namespace OpenSim.Region.UserStatistics
493 (float)agent_map["fps"].AsReal()); 500 (float)agent_map["fps"].AsReal());
494 501
495 if (mmap["downloads"].Type != OSDType.Map) 502 if (mmap["downloads"].Type != OSDType.Map)
496 return new UserSessionID(); 503 return new UserSession();
497 OSDMap downloads_map = (OSDMap)mmap["downloads"]; 504 OSDMap downloads_map = (OSDMap)mmap["downloads"];
498 usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal(); 505 usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal();
499 usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal(); 506 usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal();
500 usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal(); 507 usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal();
501 508
509// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID());
502 510
503 usd.session_id = mmap["session_id"].AsUUID(); 511 usd.session_id = mmap["session_id"].AsUUID();
504 512
505 if (mmap["system"].Type != OSDType.Map) 513 if (mmap["system"].Type != OSDType.Map)
506 return new UserSessionID(); 514 return new UserSession();
507 OSDMap system_map = (OSDMap)mmap["system"]; 515 OSDMap system_map = (OSDMap)mmap["system"];
508 516
509 usd.s_cpu = system_map["cpu"].AsString(); 517 usd.s_cpu = system_map["cpu"].AsString();
@@ -512,13 +520,13 @@ namespace OpenSim.Region.UserStatistics
512 usd.s_ram = system_map["ram"].AsInteger(); 520 usd.s_ram = system_map["ram"].AsInteger();
513 521
514 if (mmap["stats"].Type != OSDType.Map) 522 if (mmap["stats"].Type != OSDType.Map)
515 return new UserSessionID(); 523 return new UserSession();
516 524
517 OSDMap stats_map = (OSDMap)mmap["stats"]; 525 OSDMap stats_map = (OSDMap)mmap["stats"];
518 { 526 {
519 527
520 if (stats_map["failures"].Type != OSDType.Map) 528 if (stats_map["failures"].Type != OSDType.Map)
521 return new UserSessionID(); 529 return new UserSession();
522 OSDMap stats_failures = (OSDMap)stats_map["failures"]; 530 OSDMap stats_failures = (OSDMap)stats_map["failures"];
523 usd.f_dropped = stats_failures["dropped"].AsInteger(); 531 usd.f_dropped = stats_failures["dropped"].AsInteger();
524 usd.f_failed_resends = stats_failures["failed_resends"].AsInteger(); 532 usd.f_failed_resends = stats_failures["failed_resends"].AsInteger();
@@ -527,18 +535,18 @@ namespace OpenSim.Region.UserStatistics
527 usd.f_send_packet = stats_failures["send_packet"].AsInteger(); 535 usd.f_send_packet = stats_failures["send_packet"].AsInteger();
528 536
529 if (stats_map["net"].Type != OSDType.Map) 537 if (stats_map["net"].Type != OSDType.Map)
530 return new UserSessionID(); 538 return new UserSession();
531 OSDMap stats_net = (OSDMap)stats_map["net"]; 539 OSDMap stats_net = (OSDMap)stats_map["net"];
532 { 540 {
533 if (stats_net["in"].Type != OSDType.Map) 541 if (stats_net["in"].Type != OSDType.Map)
534 return new UserSessionID(); 542 return new UserSession();
535 543
536 OSDMap net_in = (OSDMap)stats_net["in"]; 544 OSDMap net_in = (OSDMap)stats_net["in"];
537 usd.n_in_kb = (float)net_in["kbytes"].AsReal(); 545 usd.n_in_kb = (float)net_in["kbytes"].AsReal();
538 usd.n_in_pk = net_in["packets"].AsInteger(); 546 usd.n_in_pk = net_in["packets"].AsInteger();
539 547
540 if (stats_net["out"].Type != OSDType.Map) 548 if (stats_net["out"].Type != OSDType.Map)
541 return new UserSessionID(); 549 return new UserSession();
542 OSDMap net_out = (OSDMap)stats_net["out"]; 550 OSDMap net_out = (OSDMap)stats_net["out"];
543 551
544 usd.n_out_kb = (float)net_out["kbytes"].AsReal(); 552 usd.n_out_kb = (float)net_out["kbytes"].AsReal();
@@ -549,11 +557,18 @@ namespace OpenSim.Region.UserStatistics
549 557
550 uid.session_data = usd; 558 uid.session_data = usd;
551 m_sessions[agentID] = uid; 559 m_sessions[agentID] = uid;
560
561// m_log.DebugFormat(
562// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
563
552 return uid; 564 return uid;
553 } 565 }
554 566
555 private void UpdateUserStats(UserSessionID uid, SqliteConnection db) 567 private void UpdateUserStats(UserSession uid, SqliteConnection db)
556 { 568 {
569// m_log.DebugFormat(
570// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
571
557 if (uid.session_id == UUID.Zero) 572 if (uid.session_id == UUID.Zero)
558 return; 573 return;
559 574
@@ -740,7 +755,6 @@ VALUES
740 s.min_ping = ArrayMin_f(__ping); 755 s.min_ping = ArrayMin_f(__ping);
741 s.max_ping = ArrayMax_f(__ping); 756 s.max_ping = ArrayMax_f(__ping);
742 s.mode_ping = ArrayMode_f(__ping); 757 s.mode_ping = ArrayMode_f(__ping);
743
744 } 758 }
745 759
746 #region Statistics 760 #region Statistics
@@ -985,7 +999,7 @@ VALUES
985 } 999 }
986 #region structs 1000 #region structs
987 1001
988 public struct UserSessionID 1002 public class UserSession
989 { 1003 {
990 public UUID session_id; 1004 public UUID session_id;
991 public UUID region_id; 1005 public UUID region_id;
diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs
index b137c05..0cff6ed 100644
--- a/OpenSim/Server/Base/ServicesServerBase.cs
+++ b/OpenSim/Server/Base/ServicesServerBase.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
29using System.IO; 30using System.IO;
30using System.Reflection; 31using System.Reflection;
31using System.Threading; 32using System.Threading;
@@ -71,10 +72,17 @@ namespace OpenSim.Server.Base
71 // 72 //
72 private string m_pidFile = String.Empty; 73 private string m_pidFile = String.Empty;
73 74
75 /// <summary>
76 /// Time at which this server was started
77 /// </summary>
78 protected DateTime m_startuptime;
79
74 // Handle all the automagical stuff 80 // Handle all the automagical stuff
75 // 81 //
76 public ServicesServerBase(string prompt, string[] args) 82 public ServicesServerBase(string prompt, string[] args)
77 { 83 {
84 m_startuptime = DateTime.Now;
85
78 // Save raw arguments 86 // Save raw arguments
79 // 87 //
80 m_Arguments = args; 88 m_Arguments = args;
@@ -250,6 +258,10 @@ namespace OpenSim.Server.Base
250 "command-script <script>", 258 "command-script <script>",
251 "Run a command script from file", HandleScript); 259 "Run a command script from file", HandleScript);
252 260
261 MainConsole.Instance.Commands.AddCommand("General", false, "show uptime",
262 "show uptime",
263 "Show server uptime", HandleShow);
264
253 265
254 // Allow derived classes to perform initialization that 266 // Allow derived classes to perform initialization that
255 // needs to be done after the console has opened 267 // needs to be done after the console has opened
@@ -345,5 +357,34 @@ namespace OpenSim.Server.Base
345 { 357 {
346 } 358 }
347 } 359 }
360
361 public virtual void HandleShow(string module, string[] cmd)
362 {
363 List<string> args = new List<string>(cmd);
364
365 args.RemoveAt(0);
366
367 string[] showParams = args.ToArray();
368
369 switch (showParams[0])
370 {
371 case "uptime":
372 MainConsole.Instance.Output(GetUptimeReport());
373 break;
374 }
375 }
376
377 /// <summary>
378 /// Return a report about the uptime of this server
379 /// </summary>
380 /// <returns></returns>
381 protected string GetUptimeReport()
382 {
383 StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now));
384 sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime));
385 sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime));
386
387 return sb.ToString();
388 }
348 } 389 }
349} 390}
diff --git a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs
index 393584e..8cd747e 100644
--- a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs
+++ b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs
@@ -137,6 +137,8 @@ namespace OpenSim.Server.Handlers.Avatar
137 if (!UUID.TryParse(request["UserID"].ToString(), out user)) 137 if (!UUID.TryParse(request["UserID"].ToString(), out user))
138 return FailureResult(); 138 return FailureResult();
139 139
140 RemoveRequestParamsNotForStorage(request);
141
140 AvatarData avatar = new AvatarData(request); 142 AvatarData avatar = new AvatarData(request);
141 if (m_AvatarService.SetAvatar(user, avatar)) 143 if (m_AvatarService.SetAvatar(user, avatar))
142 return SuccessResult(); 144 return SuccessResult();
@@ -153,11 +155,25 @@ namespace OpenSim.Server.Handlers.Avatar
153 if (!UUID.TryParse(request["UserID"].ToString(), out user)) 155 if (!UUID.TryParse(request["UserID"].ToString(), out user))
154 return FailureResult(); 156 return FailureResult();
155 157
158 RemoveRequestParamsNotForStorage(request);
159
156 if (m_AvatarService.ResetAvatar(user)) 160 if (m_AvatarService.ResetAvatar(user))
157 return SuccessResult(); 161 return SuccessResult();
158 162
159 return FailureResult(); 163 return FailureResult();
160 } 164 }
165
166 /// <summary>
167 /// Remove parameters that were used to invoke the method and should not in themselves be persisted.
168 /// </summary>
169 /// <param name='request'></param>
170 private void RemoveRequestParamsNotForStorage(Dictionary<string, object> request)
171 {
172 request.Remove("VERSIONMAX");
173 request.Remove("VERSIONMIN");
174 request.Remove("METHOD");
175 request.Remove("UserID");
176 }
161 177
162 byte[] SetItems(Dictionary<string, object> request) 178 byte[] SetItems(Dictionary<string, object> request)
163 { 179 {
@@ -173,6 +189,8 @@ namespace OpenSim.Server.Handlers.Avatar
173 if (!(request["Names"] is List<string> || request["Values"] is List<string>)) 189 if (!(request["Names"] is List<string> || request["Values"] is List<string>))
174 return FailureResult(); 190 return FailureResult();
175 191
192 RemoveRequestParamsNotForStorage(request);
193
176 List<string> _names = (List<string>)request["Names"]; 194 List<string> _names = (List<string>)request["Names"];
177 names = _names.ToArray(); 195 names = _names.ToArray();
178 List<string> _values = (List<string>)request["Values"]; 196 List<string> _values = (List<string>)request["Values"];
diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs
index 21fb678..45c13fb 100644
--- a/OpenSim/Server/ServerMain.cs
+++ b/OpenSim/Server/ServerMain.cs
@@ -60,7 +60,25 @@ namespace OpenSim.Server
60 } 60 }
61 61
62 string connList = serverConfig.GetString("ServiceConnectors", String.Empty); 62 string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
63 string[] conns = connList.Split(new char[] {',', ' '}); 63
64 IConfig servicesConfig = m_Server.Config.Configs["ServiceList"];
65 if (servicesConfig != null)
66 {
67 List<string> servicesList = new List<string>();
68 if (connList != String.Empty)
69 servicesList.Add(connList);
70
71 foreach (string k in servicesConfig.GetKeys())
72 {
73 string v = servicesConfig.GetString(k);
74 if (v != String.Empty)
75 servicesList.Add(v);
76 }
77
78 connList = String.Join(",", servicesList.ToArray());
79 }
80
81 string[] conns = connList.Split(new char[] {',', ' ', '\n', '\r', '\t'});
64 82
65// int i = 0; 83// int i = 0;
66 foreach (string c in conns) 84 foreach (string c in conns)
@@ -130,4 +148,4 @@ namespace OpenSim.Server
130 return 0; 148 return 0;
131 } 149 }
132 } 150 }
133} \ No newline at end of file 151}
diff --git a/OpenSim/Services/AssetService/AssetServiceBase.cs b/OpenSim/Services/AssetService/AssetServiceBase.cs
index 177c565..58ab052 100644
--- a/OpenSim/Services/AssetService/AssetServiceBase.cs
+++ b/OpenSim/Services/AssetService/AssetServiceBase.cs
@@ -84,7 +84,7 @@ namespace OpenSim.Services.AssetService
84 84
85 m_Database = LoadPlugin<IAssetDataPlugin>(dllName); 85 m_Database = LoadPlugin<IAssetDataPlugin>(dllName);
86 if (m_Database == null) 86 if (m_Database == null)
87 throw new Exception("Could not find a storage interface in the given module"); 87 throw new Exception(string.Format("Could not find a storage interface in the module {0}", dllName));
88 88
89 m_Database.Initialise(connString); 89 m_Database.Initialise(connString);
90 90
@@ -96,7 +96,7 @@ namespace OpenSim.Services.AssetService
96 m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName); 96 m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
97 97
98 if (m_AssetLoader == null) 98 if (m_AssetLoader == null)
99 throw new Exception("Asset loader could not be loaded"); 99 throw new Exception(string.Format("Asset loader could not be loaded from {0}", loaderName));
100 } 100 }
101 } 101 }
102 } 102 }
diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
index 7f32ad3..4b502b7 100644
--- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
+++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
@@ -52,6 +52,8 @@ namespace OpenSim.Services.Connectors
52 private int m_retryCounter; 52 private int m_retryCounter;
53 private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>(); 53 private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>();
54 private System.Timers.Timer m_retryTimer; 54 private System.Timers.Timer m_retryTimer;
55 private int m_maxAssetRequestConcurrency = 30;
56
55 private delegate void AssetRetrievedEx(AssetBase asset); 57 private delegate void AssetRetrievedEx(AssetBase asset);
56 58
57 // Keeps track of concurrent requests for the same asset, so that it's only loaded once. 59 // Keeps track of concurrent requests for the same asset, so that it's only loaded once.
@@ -80,6 +82,10 @@ namespace OpenSim.Services.Connectors
80 82
81 public virtual void Initialise(IConfigSource source) 83 public virtual void Initialise(IConfigSource source)
82 { 84 {
85 IConfig netconfig = source.Configs["Network"];
86 if (netconfig != null)
87 m_maxAssetRequestConcurrency = netconfig.GetInt("MaxRequestConcurrency",m_maxAssetRequestConcurrency);
88
83 IConfig assetConfig = source.Configs["AssetService"]; 89 IConfig assetConfig = source.Configs["AssetService"];
84 if (assetConfig == null) 90 if (assetConfig == null)
85 { 91 {
@@ -204,7 +210,7 @@ namespace OpenSim.Services.Connectors
204 if (asset == null || asset.Data == null || asset.Data.Length == 0) 210 if (asset == null || asset.Data == null || asset.Data.Length == 0)
205 { 211 {
206 asset = SynchronousRestObjectRequester. 212 asset = SynchronousRestObjectRequester.
207 MakeRequest<int, AssetBase>("GET", uri, 0, 30); 213 MakeRequest<int, AssetBase>("GET", uri, 0, m_maxAssetRequestConcurrency);
208 214
209 if (m_Cache != null) 215 if (m_Cache != null)
210 m_Cache.Cache(asset); 216 m_Cache.Cache(asset);
diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
index 6cd21d1..4ec1edc 100644
--- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
+++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs
@@ -154,7 +154,7 @@ namespace OpenSim.Services.Connectors.Friends
154 if (!region.ServerURI.EndsWith("/")) 154 if (!region.ServerURI.EndsWith("/"))
155 path = "/" + path; 155 path = "/" + path;
156 string uri = region.ServerURI + path; 156 string uri = region.ServerURI + path;
157 m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: calling {0}", uri); 157 // m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: calling {0}", uri);
158 158
159 try 159 try
160 { 160 {
diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs
index 20d7eaf..94bda82 100644
--- a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs
+++ b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs
@@ -207,7 +207,7 @@ namespace OpenSim.Services.Connectors
207 if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) 207 if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null))
208 { 208 {
209 if (replyData["result"] is Dictionary<string, object>) 209 if (replyData["result"] is Dictionary<string, object>)
210 guinfo = new GridUserInfo((Dictionary<string, object>)replyData["result"]); 210 guinfo = Create((Dictionary<string, object>)replyData["result"]);
211 } 211 }
212 212
213 return guinfo; 213 return guinfo;
@@ -273,7 +273,7 @@ namespace OpenSim.Services.Connectors
273 { 273 {
274 if (griduser is Dictionary<string, object>) 274 if (griduser is Dictionary<string, object>)
275 { 275 {
276 GridUserInfo pinfo = new GridUserInfo((Dictionary<string, object>)griduser); 276 GridUserInfo pinfo = Create((Dictionary<string, object>)griduser);
277 rinfos.Add(pinfo); 277 rinfos.Add(pinfo);
278 } 278 }
279 else 279 else
@@ -286,5 +286,10 @@ namespace OpenSim.Services.Connectors
286 286
287 return rinfos.ToArray(); 287 return rinfos.ToArray();
288 } 288 }
289
290 protected virtual GridUserInfo Create(Dictionary<string, object> griduser)
291 {
292 return new GridUserInfo(griduser);
293 }
289 } 294 }
290} 295}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
index 0e4d794..20eaa3a 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -112,7 +112,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
112// m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking"); 112// m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking");
113 113
114 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); 114 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0);
115 Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, 4096.0); 115 Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
116 116
117 OSDMap extraData = new OSDMap 117 OSDMap extraData = new OSDMap
118 { 118 {
@@ -297,7 +297,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
297 List<GridRegion> foundRegions = new List<GridRegion>(); 297 List<GridRegion> foundRegions = new List<GridRegion>();
298 298
299 Vector3d minPosition = new Vector3d(xmin, ymin, 0.0); 299 Vector3d minPosition = new Vector3d(xmin, ymin, 0.0);
300 Vector3d maxPosition = new Vector3d(xmax, ymax, 4096.0); 300 Vector3d maxPosition = new Vector3d(xmax, ymax, Constants.RegionHeight);
301 301
302 NameValueCollection requestArgs = new NameValueCollection 302 NameValueCollection requestArgs = new NameValueCollection
303 { 303 {
@@ -395,8 +395,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
395 if (response["Success"].AsBoolean()) 395 if (response["Success"].AsBoolean())
396 { 396 {
397 OSDMap extraData = response["ExtraData"] as OSDMap; 397 OSDMap extraData = response["ExtraData"] as OSDMap;
398 int enabled = response["Enabled"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.RegionOnline : 0; 398 int enabled = response["Enabled"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.RegionOnline : 0;
399 int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.Hyperlink : 0; 399 int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.Hyperlink : 0;
400 int flags = enabled | hypergrid; 400 int flags = enabled | hypergrid;
401 m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags); 401 m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags);
402 return flags; 402 return flags;
diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs
index aab403a..ee3b858 100644
--- a/OpenSim/Services/GridService/GridService.cs
+++ b/OpenSim/Services/GridService/GridService.cs
@@ -137,20 +137,25 @@ namespace OpenSim.Services.GridService
137 if (regionInfos.RegionID == UUID.Zero) 137 if (regionInfos.RegionID == UUID.Zero)
138 return "Invalid RegionID - cannot be zero UUID"; 138 return "Invalid RegionID - cannot be zero UUID";
139 139
140 // This needs better sanity testing. What if regionInfo is registering in
141 // overlapping coords?
142 RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); 140 RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID);
141 if ((region != null) && (region.RegionID != regionInfos.RegionID))
142 {
143 m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register in coordinates {1}, {2} which are already in use in scope {3}.",
144 regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID);
145 return "Region overlaps another region";
146 }
147
143 if (region != null) 148 if (region != null)
144 { 149 {
145 // There is a preexisting record 150 // There is a preexisting record
146 // 151 //
147 // Get it's flags 152 // Get it's flags
148 // 153 //
149 OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(region.Data["flags"]); 154 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(region.Data["flags"]);
150 155
151 // Is this a reservation? 156 // Is this a reservation?
152 // 157 //
153 if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) 158 if ((rflags & OpenSim.Framework.RegionFlags.Reservation) != 0)
154 { 159 {
155 // Regions reserved for the null key cannot be taken. 160 // Regions reserved for the null key cannot be taken.
156 if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) 161 if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString())
@@ -161,10 +166,10 @@ namespace OpenSim.Services.GridService
161 // NOTE: Fudging the flags value here, so these flags 166 // NOTE: Fudging the flags value here, so these flags
162 // should not be used elsewhere. Don't optimize 167 // should not be used elsewhere. Don't optimize
163 // this with the later retrieval of the same flags! 168 // this with the later retrieval of the same flags!
164 rflags |= OpenSim.Data.RegionFlags.Authenticate; 169 rflags |= OpenSim.Framework.RegionFlags.Authenticate;
165 } 170 }
166 171
167 if ((rflags & OpenSim.Data.RegionFlags.Authenticate) != 0) 172 if ((rflags & OpenSim.Framework.RegionFlags.Authenticate) != 0)
168 { 173 {
169 // Can we authenticate at all? 174 // Can we authenticate at all?
170 // 175 //
@@ -176,19 +181,36 @@ namespace OpenSim.Services.GridService
176 } 181 }
177 } 182 }
178 183
179 if ((region != null) && (region.RegionID != regionInfos.RegionID)) 184 // If we get here, the destination is clear. Now for the real check.
185
186 if (!m_AllowDuplicateNames)
180 { 187 {
181 m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register in coordinates {1}, {2} which are already in use in scope {3}.", 188 List<RegionData> dupe = m_Database.Get(regionInfos.RegionName, scopeID);
182 regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); 189 if (dupe != null && dupe.Count > 0)
183 return "Region overlaps another region"; 190 {
191 foreach (RegionData d in dupe)
192 {
193 if (d.RegionID != regionInfos.RegionID)
194 {
195 m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register duplicate name with ID {1}.",
196 regionInfos.RegionName, regionInfos.RegionID);
197 return "Duplicate region name";
198 }
199 }
200 }
184 } 201 }
185 202
203 // If there is an old record for us, delete it if it is elsewhere.
204 region = m_Database.Get(regionInfos.RegionID, scopeID);
186 if ((region != null) && (region.RegionID == regionInfos.RegionID) && 205 if ((region != null) && (region.RegionID == regionInfos.RegionID) &&
187 ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY))) 206 ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY)))
188 { 207 {
189 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.NoMove) != 0) 208 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.NoMove) != 0)
190 return "Can't move this region"; 209 return "Can't move this region";
191 210
211 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.LockedOut) != 0)
212 return "Region locked out";
213
192 // Region reregistering in other coordinates. Delete the old entry 214 // Region reregistering in other coordinates. Delete the old entry
193 m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.", 215 m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.",
194 regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY); 216 regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY);
@@ -203,23 +225,6 @@ namespace OpenSim.Services.GridService
203 } 225 }
204 } 226 }
205 227
206 if (!m_AllowDuplicateNames)
207 {
208 List<RegionData> dupe = m_Database.Get(regionInfos.RegionName, scopeID);
209 if (dupe != null && dupe.Count > 0)
210 {
211 foreach (RegionData d in dupe)
212 {
213 if (d.RegionID != regionInfos.RegionID)
214 {
215 m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register duplicate name with ID {1}.",
216 regionInfos.RegionName, regionInfos.RegionID);
217 return "Duplicate region name";
218 }
219 }
220 }
221 }
222
223 // Everything is ok, let's register 228 // Everything is ok, let's register
224 RegionData rdata = RegionInfo2RegionData(regionInfos); 229 RegionData rdata = RegionInfo2RegionData(regionInfos);
225 rdata.ScopeID = scopeID; 230 rdata.ScopeID = scopeID;
@@ -227,10 +232,8 @@ namespace OpenSim.Services.GridService
227 if (region != null) 232 if (region != null)
228 { 233 {
229 int oldFlags = Convert.ToInt32(region.Data["flags"]); 234 int oldFlags = Convert.ToInt32(region.Data["flags"]);
230 if ((oldFlags & (int)OpenSim.Data.RegionFlags.LockedOut) != 0)
231 return "Region locked out";
232 235
233 oldFlags &= ~(int)OpenSim.Data.RegionFlags.Reservation; 236 oldFlags &= ~(int)OpenSim.Framework.RegionFlags.Reservation;
234 237
235 rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags 238 rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags
236 } 239 }
@@ -249,7 +252,7 @@ namespace OpenSim.Services.GridService
249 } 252 }
250 253
251 int flags = Convert.ToInt32(rdata.Data["flags"]); 254 int flags = Convert.ToInt32(rdata.Data["flags"]);
252 flags |= (int)OpenSim.Data.RegionFlags.RegionOnline; 255 flags |= (int)OpenSim.Framework.RegionFlags.RegionOnline;
253 rdata.Data["flags"] = flags.ToString(); 256 rdata.Data["flags"] = flags.ToString();
254 257
255 try 258 try
@@ -280,9 +283,9 @@ namespace OpenSim.Services.GridService
280 283
281 int flags = Convert.ToInt32(region.Data["flags"]); 284 int flags = Convert.ToInt32(region.Data["flags"]);
282 285
283 if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Data.RegionFlags.Persistent) != 0) 286 if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Framework.RegionFlags.Persistent) != 0)
284 { 287 {
285 flags &= ~(int)OpenSim.Data.RegionFlags.RegionOnline; 288 flags &= ~(int)OpenSim.Framework.RegionFlags.RegionOnline;
286 region.Data["flags"] = flags.ToString(); 289 region.Data["flags"] = flags.ToString();
287 region.Data["last_seen"] = Util.UnixTimeSinceEpoch(); 290 region.Data["last_seen"] = Util.UnixTimeSinceEpoch();
288 try 291 try
@@ -317,7 +320,7 @@ namespace OpenSim.Services.GridService
317 if (rdata.RegionID != regionID) 320 if (rdata.RegionID != regionID)
318 { 321 {
319 int flags = Convert.ToInt32(rdata.Data["flags"]); 322 int flags = Convert.ToInt32(rdata.Data["flags"]);
320 if ((flags & (int)Data.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours 323 if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
321 rinfos.Add(RegionData2RegionInfo(rdata)); 324 rinfos.Add(RegionData2RegionInfo(rdata));
322 } 325 }
323 } 326 }
@@ -467,7 +470,7 @@ namespace OpenSim.Services.GridService
467 470
468 foreach (RegionData r in regions) 471 foreach (RegionData r in regions)
469 { 472 {
470 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 473 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
471 ret.Add(RegionData2RegionInfo(r)); 474 ret.Add(RegionData2RegionInfo(r));
472 } 475 }
473 476
@@ -483,7 +486,7 @@ namespace OpenSim.Services.GridService
483 486
484 foreach (RegionData r in regions) 487 foreach (RegionData r in regions)
485 { 488 {
486 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 489 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
487 ret.Add(RegionData2RegionInfo(r)); 490 ret.Add(RegionData2RegionInfo(r));
488 } 491 }
489 492
@@ -499,7 +502,7 @@ namespace OpenSim.Services.GridService
499 502
500 foreach (RegionData r in regions) 503 foreach (RegionData r in regions)
501 { 504 {
502 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 505 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
503 ret.Add(RegionData2RegionInfo(r)); 506 ret.Add(RegionData2RegionInfo(r));
504 } 507 }
505 508
@@ -626,7 +629,7 @@ namespace OpenSim.Services.GridService
626 629
627 private void OutputRegionToConsole(RegionData r) 630 private void OutputRegionToConsole(RegionData r)
628 { 631 {
629 OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); 632 OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
630 633
631 ConsoleDisplayList dispList = new ConsoleDisplayList(); 634 ConsoleDisplayList dispList = new ConsoleDisplayList();
632 dispList.AddRow("Region Name", r.RegionName); 635 dispList.AddRow("Region Name", r.RegionName);
@@ -656,7 +659,7 @@ namespace OpenSim.Services.GridService
656 659
657 foreach (RegionData r in regions) 660 foreach (RegionData r in regions)
658 { 661 {
659 OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); 662 OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
660 dispTable.AddRow( 663 dispTable.AddRow(
661 r.RegionName, 664 r.RegionName,
662 r.RegionID.ToString(), 665 r.RegionID.ToString(),
@@ -670,7 +673,7 @@ namespace OpenSim.Services.GridService
670 673
671 private int ParseFlags(int prev, string flags) 674 private int ParseFlags(int prev, string flags)
672 { 675 {
673 OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)prev; 676 OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)prev;
674 677
675 string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries); 678 string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
676 679
@@ -682,18 +685,18 @@ namespace OpenSim.Services.GridService
682 { 685 {
683 if (p.StartsWith("+")) 686 if (p.StartsWith("+"))
684 { 687 {
685 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); 688 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
686 f |= (OpenSim.Data.RegionFlags)val; 689 f |= (OpenSim.Framework.RegionFlags)val;
687 } 690 }
688 else if (p.StartsWith("-")) 691 else if (p.StartsWith("-"))
689 { 692 {
690 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); 693 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
691 f &= ~(OpenSim.Data.RegionFlags)val; 694 f &= ~(OpenSim.Framework.RegionFlags)val;
692 } 695 }
693 else 696 else
694 { 697 {
695 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p); 698 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p);
696 f |= (OpenSim.Data.RegionFlags)val; 699 f |= (OpenSim.Framework.RegionFlags)val;
697 } 700 }
698 } 701 }
699 catch (Exception) 702 catch (Exception)
@@ -725,7 +728,7 @@ namespace OpenSim.Services.GridService
725 int flags = Convert.ToInt32(r.Data["flags"]); 728 int flags = Convert.ToInt32(r.Data["flags"]);
726 flags = ParseFlags(flags, cmd[4]); 729 flags = ParseFlags(flags, cmd[4]);
727 r.Data["flags"] = flags.ToString(); 730 r.Data["flags"] = flags.ToString();
728 OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)flags; 731 OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)flags;
729 732
730 MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f)); 733 MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f));
731 m_Database.Store(r); 734 m_Database.Store(r);
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs
index 78eab3d..743d089 100644
--- a/OpenSim/Services/GridService/HypergridLinker.cs
+++ b/OpenSim/Services/GridService/HypergridLinker.cs
@@ -390,8 +390,8 @@ namespace OpenSim.Services.GridService
390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); 390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID);
391 if (regions != null && regions.Count > 0) 391 if (regions != null && regions.Count > 0)
392 { 392 {
393 OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); 393 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
394 if ((rflags & OpenSim.Data.RegionFlags.Hyperlink) != 0) 394 if ((rflags & OpenSim.Framework.RegionFlags.Hyperlink) != 0)
395 { 395 {
396 regInfo = new GridRegion(); 396 regInfo = new GridRegion();
397 regInfo.RegionID = regions[0].RegionID; 397 regInfo.RegionID = regions[0].RegionID;
@@ -460,7 +460,7 @@ namespace OpenSim.Services.GridService
460 private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle) 460 private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle)
461 { 461 {
462 RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo); 462 RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo);
463 int flags = (int)OpenSim.Data.RegionFlags.Hyperlink + (int)OpenSim.Data.RegionFlags.NoDirectLogin + (int)OpenSim.Data.RegionFlags.RegionOnline; 463 int flags = (int)OpenSim.Framework.RegionFlags.Hyperlink + (int)OpenSim.Framework.RegionFlags.NoDirectLogin + (int)OpenSim.Framework.RegionFlags.RegionOnline;
464 rdata.Data["flags"] = flags.ToString(); 464 rdata.Data["flags"] = flags.ToString();
465 465
466 m_Database.Store(rdata); 466 m_Database.Store(rdata);
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
index 47d22b9..004311f 100644
--- a/OpenSim/Services/HypergridService/GatekeeperService.cs
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -57,10 +57,13 @@ namespace OpenSim.Services.HypergridService
57 private static IUserAccountService m_UserAccountService; 57 private static IUserAccountService m_UserAccountService;
58 private static IUserAgentService m_UserAgentService; 58 private static IUserAgentService m_UserAgentService;
59 private static ISimulationService m_SimulationService; 59 private static ISimulationService m_SimulationService;
60 private static IGridUserService m_GridUserService;
60 61
61 protected string m_AllowedClients = string.Empty; 62 private static string m_AllowedClients = string.Empty;
62 protected string m_DeniedClients = string.Empty; 63 private static string m_DeniedClients = string.Empty;
63 private static bool m_ForeignAgentsAllowed = true; 64 private static bool m_ForeignAgentsAllowed = true;
65 private static List<string> m_ForeignsAllowedExceptions = new List<string>();
66 private static List<string> m_ForeignsDisallowedExceptions = new List<string>();
64 67
65 private static UUID m_ScopeID; 68 private static UUID m_ScopeID;
66 private static bool m_AllowTeleportsToAnyRegion; 69 private static bool m_AllowTeleportsToAnyRegion;
@@ -82,8 +85,9 @@ namespace OpenSim.Services.HypergridService
82 string gridService = serverConfig.GetString("GridService", String.Empty); 85 string gridService = serverConfig.GetString("GridService", String.Empty);
83 string presenceService = serverConfig.GetString("PresenceService", String.Empty); 86 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
84 string simulationService = serverConfig.GetString("SimulationService", String.Empty); 87 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
88 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
85 89
86 // These 3 are mandatory, the others aren't 90 // These are mandatory, the others aren't
87 if (gridService == string.Empty || presenceService == string.Empty) 91 if (gridService == string.Empty || presenceService == string.Empty)
88 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function."); 92 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
89 93
@@ -103,6 +107,8 @@ namespace OpenSim.Services.HypergridService
103 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); 107 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
104 if (homeUsersService != string.Empty) 108 if (homeUsersService != string.Empty)
105 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args); 109 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
110 if (gridUserService != string.Empty)
111 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
106 112
107 if (simService != null) 113 if (simService != null)
108 m_SimulationService = simService; 114 m_SimulationService = simService;
@@ -113,6 +119,9 @@ namespace OpenSim.Services.HypergridService
113 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty); 119 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
114 m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true); 120 m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
115 121
122 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
123 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
124
116 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null) 125 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
117 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function."); 126 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
118 127
@@ -125,6 +134,15 @@ namespace OpenSim.Services.HypergridService
125 { 134 {
126 } 135 }
127 136
137 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
138 {
139 string value = config.GetString(variable, string.Empty);
140 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
141
142 foreach (string s in parts)
143 exceptions.Add(s.Trim());
144 }
145
128 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason) 146 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
129 { 147 {
130 regionID = UUID.Zero; 148 regionID = UUID.Zero;
@@ -260,17 +278,26 @@ namespace OpenSim.Services.HypergridService
260 m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok"); 278 m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok");
261 279
262 // 280 //
263 // Foreign agents allowed 281 // Foreign agents allowed? Exceptions?
264 // 282 //
265 if (account == null && !m_ForeignAgentsAllowed) 283 if (account == null)
266 { 284 {
267 reason = "Unauthorized"; 285 bool allowed = m_ForeignAgentsAllowed;
268 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1}. Refusing service.", 286
269 aCircuit.firstname, aCircuit.lastname); 287 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
270 return false; 288 allowed = false;
271 }
272 289
273 // May want to authorize 290 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
291 allowed = true;
292
293 if (!allowed)
294 {
295 reason = "Destination does not allow visitors from your world";
296 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
297 aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
298 return false;
299 }
300 }
274 301
275 bool isFirstLogin = false; 302 bool isFirstLogin = false;
276 // 303 //
@@ -280,7 +307,8 @@ namespace OpenSim.Services.HypergridService
280 if (presence != null) // it has been placed there by the login service 307 if (presence != null) // it has been placed there by the login service
281 isFirstLogin = true; 308 isFirstLogin = true;
282 309
283 else 310 else
311 {
284 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID)) 312 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
285 { 313 {
286 reason = "Unable to login presence"; 314 reason = "Unable to login presence";
@@ -290,6 +318,26 @@ namespace OpenSim.Services.HypergridService
290 } 318 }
291 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); 319 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok");
292 320
321 // Also login foreigners with GridUser service
322 if (m_GridUserService != null && account == null)
323 {
324 string userId = aCircuit.AgentID.ToString();
325 string first = aCircuit.firstname, last = aCircuit.lastname;
326 if (last.StartsWith("@"))
327 {
328 string[] parts = aCircuit.firstname.Split('.');
329 if (parts.Length >= 2)
330 {
331 first = parts[0];
332 last = parts[1];
333 }
334 }
335
336 userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
337 m_GridUserService.LoggedIn(userId);
338 }
339 }
340
293 // 341 //
294 // Get the region 342 // Get the region
295 // 343 //
@@ -393,6 +441,27 @@ namespace OpenSim.Services.HypergridService
393 441
394 #region Misc 442 #region Misc
395 443
444 private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
445 {
446 bool exception = false;
447 if (exceptions.Count > 0) // we have exceptions
448 {
449 // Retrieve the visitor's origin
450 string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
451 if (!userURL.EndsWith("/"))
452 userURL += "/";
453
454 if (exceptions.Find(delegate(string s)
455 {
456 if (!s.EndsWith("/"))
457 s += "/";
458 return s == userURL;
459 }) != null)
460 exception = true;
461 }
462
463 return exception;
464 }
396 465
397 #endregion 466 #endregion
398 } 467 }
diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs
index db98166..84dec8d 100644
--- a/OpenSim/Services/HypergridService/HGAssetService.cs
+++ b/OpenSim/Services/HypergridService/HGAssetService.cs
@@ -58,6 +58,8 @@ namespace OpenSim.Services.HypergridService
58 58
59 private UserAccountCache m_Cache; 59 private UserAccountCache m_Cache;
60 60
61 private AssetPermissions m_AssetPerms;
62
61 public HGAssetService(IConfigSource config, string configName) : base(config, configName) 63 public HGAssetService(IConfigSource config, string configName) : base(config, configName)
62 { 64 {
63 m_log.Debug("[HGAsset Service]: Starting"); 65 m_log.Debug("[HGAsset Service]: Starting");
@@ -80,6 +82,10 @@ namespace OpenSim.Services.HypergridService
80 m_HomeURL = assetConfig.GetString("HomeURI", m_HomeURL); 82 m_HomeURL = assetConfig.GetString("HomeURI", m_HomeURL);
81 83
82 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); 84 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
85
86 // Permissions
87 m_AssetPerms = new AssetPermissions(assetConfig);
88
83 } 89 }
84 90
85 #region IAssetService overrides 91 #region IAssetService overrides
@@ -90,6 +96,9 @@ namespace OpenSim.Services.HypergridService
90 if (asset == null) 96 if (asset == null)
91 return null; 97 return null;
92 98
99 if (!m_AssetPerms.AllowedExport(asset.Type))
100 return null;
101
93 if (asset.Metadata.Type == (sbyte)AssetType.Object) 102 if (asset.Metadata.Type == (sbyte)AssetType.Object)
94 asset.Data = AdjustIdentifiers(asset.Data); ; 103 asset.Data = AdjustIdentifiers(asset.Data); ;
95 104
@@ -112,16 +121,27 @@ namespace OpenSim.Services.HypergridService
112 121
113 public override byte[] GetData(string id) 122 public override byte[] GetData(string id)
114 { 123 {
115 byte[] data = base.GetData(id); 124 AssetBase asset = Get(id);
125
126 if (asset == null)
127 return null;
116 128
117 if (data == null) 129 if (!m_AssetPerms.AllowedExport(asset.Type))
118 return null; 130 return null;
119 131
120 return AdjustIdentifiers(data); 132 return asset.Data;
121 } 133 }
122 134
123 //public virtual bool Get(string id, Object sender, AssetRetrieved handler) 135 //public virtual bool Get(string id, Object sender, AssetRetrieved handler)
124 136
137 public override string Store(AssetBase asset)
138 {
139 if (!m_AssetPerms.AllowedImport(asset.Type))
140 return string.Empty;
141
142 return base.Store(asset);
143 }
144
125 public override bool Delete(string id) 145 public override bool Delete(string id)
126 { 146 {
127 // NOGO 147 // NOGO
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
index 6e4b68c..556a0da 100644
--- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -56,10 +56,12 @@ namespace OpenSim.Services.HypergridService
56 56
57 private string m_HomeURL; 57 private string m_HomeURL;
58 private IUserAccountService m_UserAccountService; 58 private IUserAccountService m_UserAccountService;
59 private IAvatarService m_AvatarService;
59 60
60// private UserAccountCache m_Cache; 61// private UserAccountCache m_Cache;
61 62
62 private ExpiringCache<UUID, List<XInventoryFolder>> m_SuitcaseTrees = new ExpiringCache<UUID, List<XInventoryFolder>>(); 63 private ExpiringCache<UUID, List<XInventoryFolder>> m_SuitcaseTrees = new ExpiringCache<UUID, List<XInventoryFolder>>();
64 private ExpiringCache<UUID, AvatarAppearance> m_Appearances = new ExpiringCache<UUID, AvatarAppearance>();
63 65
64 public HGSuitcaseInventoryService(IConfigSource config, string configName) 66 public HGSuitcaseInventoryService(IConfigSource config, string configName)
65 : base(config, configName) 67 : base(config, configName)
@@ -77,7 +79,6 @@ namespace OpenSim.Services.HypergridService
77 IConfig invConfig = config.Configs[m_ConfigName]; 79 IConfig invConfig = config.Configs[m_ConfigName];
78 if (invConfig != null) 80 if (invConfig != null)
79 { 81 {
80 // realm = authConfig.GetString("Realm", realm);
81 string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty); 82 string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty);
82 if (userAccountsDll == string.Empty) 83 if (userAccountsDll == string.Empty)
83 throw new Exception("Please specify UserAccountsService in HGInventoryService configuration"); 84 throw new Exception("Please specify UserAccountsService in HGInventoryService configuration");
@@ -87,8 +88,14 @@ namespace OpenSim.Services.HypergridService
87 if (m_UserAccountService == null) 88 if (m_UserAccountService == null)
88 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); 89 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
89 90
90 // legacy configuration [obsolete] 91 string avatarDll = invConfig.GetString("AvatarService", string.Empty);
91 m_HomeURL = invConfig.GetString("ProfileServerURI", string.Empty); 92 if (avatarDll == string.Empty)
93 throw new Exception("Please specify AvatarService in HGInventoryService configuration");
94
95 m_AvatarService = ServerUtils.LoadPlugin<IAvatarService>(avatarDll, args);
96 if (m_AvatarService == null)
97 throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll));
98
92 // Preferred 99 // Preferred
93 m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); 100 m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL);
94 101
@@ -394,7 +401,7 @@ namespace OpenSim.Services.HypergridService
394 return null; 401 return null;
395 } 402 }
396 403
397 if (!IsWithinSuitcaseTree(it.Owner, it.Folder)) 404 if (!IsWithinSuitcaseTree(it.Owner, it.Folder) && !IsPartOfAppearance(it.Owner, it.ID))
398 { 405 {
399 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Item {0} (folder {1}) is not within Suitcase", 406 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Item {0} (folder {1}) is not within Suitcase",
400 it.Name, it.Folder); 407 it.Name, it.Folder);
@@ -549,6 +556,52 @@ namespace OpenSim.Services.HypergridService
549 else return true; 556 else return true;
550 } 557 }
551 #endregion 558 #endregion
559
560 #region Avatar Appearance
561
562 private AvatarAppearance GetAppearance(UUID principalID)
563 {
564 AvatarAppearance a = null;
565 if (m_Appearances.TryGetValue(principalID, out a))
566 return a;
567
568 a = m_AvatarService.GetAppearance(principalID);
569 m_Appearances.AddOrUpdate(principalID, a, 5 * 60); // 5minutes
570 return a;
571 }
572
573 private bool IsPartOfAppearance(UUID principalID, UUID itemID)
574 {
575 AvatarAppearance a = GetAppearance(principalID);
576
577 if (a == null)
578 return false;
579
580 // Check wearables (body parts and clothes)
581 for (int i = 0; i < a.Wearables.Length; i++)
582 {
583 for (int j = 0; j < a.Wearables[i].Count; j++)
584 {
585 if (a.Wearables[i][j].ItemID == itemID)
586 {
587 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is a wearable", itemID);
588 return true;
589 }
590 }
591 }
592
593 // Check attachments
594 if (a.GetAttachmentForItem(itemID) != null)
595 {
596 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is an attachment", itemID);
597 return true;
598 }
599
600 return false;
601 }
602
603 #endregion
604
552 } 605 }
553 606
554} 607}
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
index a49993c..56aafe6 100644
--- a/OpenSim/Services/HypergridService/UserAgentService.cs
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -77,6 +77,10 @@ namespace OpenSim.Services.HypergridService
77 77
78 protected static bool m_BypassClientVerification; 78 protected static bool m_BypassClientVerification;
79 79
80 private static Dictionary<int, bool> m_ForeignTripsAllowed = new Dictionary<int, bool>();
81 private static Dictionary<int, List<string>> m_TripsAllowedExceptions = new Dictionary<int, List<string>>();
82 private static Dictionary<int, List<string>> m_TripsDisallowedExceptions = new Dictionary<int, List<string>>();
83
80 public UserAgentService(IConfigSource config) : this(config, null) 84 public UserAgentService(IConfigSource config) : this(config, null)
81 { 85 {
82 } 86 }
@@ -121,6 +125,12 @@ namespace OpenSim.Services.HypergridService
121 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); 125 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
122 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args); 126 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args);
123 127
128 m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0);
129
130 LoadTripPermissionsFromConfig(serverConfig, "ForeignTripsAllowed");
131 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions);
132 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions);
133
124 m_GridName = serverConfig.GetString("ExternalName", string.Empty); 134 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
125 if (m_GridName == string.Empty) 135 if (m_GridName == string.Empty)
126 { 136 {
@@ -130,10 +140,43 @@ namespace OpenSim.Services.HypergridService
130 if (!m_GridName.EndsWith("/")) 140 if (!m_GridName.EndsWith("/"))
131 m_GridName = m_GridName + "/"; 141 m_GridName = m_GridName + "/";
132 142
133 m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0);
134 } 143 }
135 } 144 }
136 145
146 protected void LoadTripPermissionsFromConfig(IConfig config, string variable)
147 {
148 foreach (string keyName in config.GetKeys())
149 {
150 if (keyName.StartsWith(variable + "_Level_"))
151 {
152 int level = 0;
153 if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level))
154 m_ForeignTripsAllowed.Add(level, config.GetBoolean(keyName, true));
155 }
156 }
157 }
158
159 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, Dictionary<int, List<string>> exceptions)
160 {
161 foreach (string keyName in config.GetKeys())
162 {
163 if (keyName.StartsWith(variable + "_Level_"))
164 {
165 int level = 0;
166 if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level) && !exceptions.ContainsKey(level))
167 {
168 exceptions.Add(level, new List<string>());
169 string value = config.GetString(keyName, string.Empty);
170 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
171
172 foreach (string s in parts)
173 exceptions[level].Add(s.Trim());
174 }
175 }
176 }
177 }
178
179
137 public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) 180 public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt)
138 { 181 {
139 position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY; 182 position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY;
@@ -166,13 +209,39 @@ namespace OpenSim.Services.HypergridService
166 m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", 209 m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}",
167 agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); 210 agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI);
168 211
169 if (m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID) == null) 212 string gridName = gatekeeper.ServerURI;
213
214 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID);
215 if (account == null)
170 { 216 {
171 m_log.WarnFormat("[USER AGENT SERVICE]: Someone attempted to lauch a foreign user from here {0} {1}", agentCircuit.firstname, agentCircuit.lastname); 217 m_log.WarnFormat("[USER AGENT SERVICE]: Someone attempted to lauch a foreign user from here {0} {1}", agentCircuit.firstname, agentCircuit.lastname);
172 reason = "Forbidden to launch your agents from here"; 218 reason = "Forbidden to launch your agents from here";
173 return false; 219 return false;
174 } 220 }
175 221
222 // Is this user allowed to go there?
223 if (m_GridName != gridName)
224 {
225 if (m_ForeignTripsAllowed.ContainsKey(account.UserLevel))
226 {
227 bool allowed = m_ForeignTripsAllowed[account.UserLevel];
228
229 if (m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsAllowedExceptions))
230 allowed = false;
231
232 if (!m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsDisallowedExceptions))
233 allowed = true;
234
235 if (!allowed)
236 {
237 reason = "Your world does not allow you to visit the destination";
238 m_log.InfoFormat("[USER AGENT SERVICE]: Agents not permitted to visit {0}. Refusing service.", gridName);
239 return false;
240 }
241 }
242 }
243
244
176 // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination 245 // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination
177 GridRegion region = new GridRegion(gatekeeper); 246 GridRegion region = new GridRegion(gatekeeper);
178 region.ServerURI = gatekeeper.ServerURI; 247 region.ServerURI = gatekeeper.ServerURI;
@@ -189,7 +258,6 @@ namespace OpenSim.Services.HypergridService
189 258
190 bool success = false; 259 bool success = false;
191 string myExternalIP = string.Empty; 260 string myExternalIP = string.Empty;
192 string gridName = gatekeeper.ServerURI;
193 261
194 m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); 262 m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName);
195 263
@@ -586,6 +654,35 @@ namespace OpenSim.Services.HypergridService
586 else 654 else
587 return UUID.Zero; 655 return UUID.Zero;
588 } 656 }
657
658 #region Misc
659
660 private bool IsException(string dest, int level, Dictionary<int, List<string>> exceptions)
661 {
662 if (!exceptions.ContainsKey(level))
663 return false;
664
665 bool exception = false;
666 if (exceptions[level].Count > 0) // we have exceptions
667 {
668 string destination = dest;
669 if (!destination.EndsWith("/"))
670 destination += "/";
671
672 if (exceptions[level].Find(delegate(string s)
673 {
674 if (!s.EndsWith("/"))
675 s += "/";
676 return s == destination;
677 }) != null)
678 exception = true;
679 }
680
681 return exception;
682 }
683
684 #endregion
685
589 } 686 }
590 687
591 class TravelingAgentInfo 688 class TravelingAgentInfo
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs
index cdcb961..3f4c958 100644
--- a/OpenSim/Services/Interfaces/IGridService.cs
+++ b/OpenSim/Services/Interfaces/IGridService.cs
@@ -100,6 +100,19 @@ namespace OpenSim.Services.Interfaces
100 List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y); 100 List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
101 List<GridRegion> GetHyperlinks(UUID scopeID); 101 List<GridRegion> GetHyperlinks(UUID scopeID);
102 102
103 /// <summary>
104 /// Get internal OpenSimulator region flags.
105 /// </summary>
106 /// <remarks>
107 /// See OpenSimulator.Framework.RegionFlags. These are not returned in the GridRegion structure -
108 /// they currently need to be requested separately. Possibly this should change to avoid multiple service calls
109 /// in some situations.
110 /// </remarks>
111 /// <returns>
112 /// The region flags.
113 /// </returns>
114 /// <param name='scopeID'></param>
115 /// <param name='regionID'></param>
103 int GetRegionFlags(UUID scopeID, UUID regionID); 116 int GetRegionFlags(UUID scopeID, UUID regionID);
104 } 117 }
105 118
diff --git a/OpenSim/Services/Interfaces/IGridUserService.cs b/OpenSim/Services/Interfaces/IGridUserService.cs
index 0a52bfa..2e7237e 100644
--- a/OpenSim/Services/Interfaces/IGridUserService.cs
+++ b/OpenSim/Services/Interfaces/IGridUserService.cs
@@ -80,7 +80,7 @@ namespace OpenSim.Services.Interfaces
80 80
81 } 81 }
82 82
83 public Dictionary<string, object> ToKeyValuePairs() 83 public virtual Dictionary<string, object> ToKeyValuePairs()
84 { 84 {
85 Dictionary<string, object> result = new Dictionary<string, object>(); 85 Dictionary<string, object> result = new Dictionary<string, object>();
86 result["UserID"] = UserID; 86 result["UserID"] = UserID;
@@ -96,7 +96,6 @@ namespace OpenSim.Services.Interfaces
96 result["Online"] = Online.ToString(); 96 result["Online"] = Online.ToString();
97 result["Login"] = Login.ToString(); 97 result["Login"] = Login.ToString();
98 result["Logout"] = Logout.ToString(); 98 result["Logout"] = Logout.ToString();
99
100 99
101 return result; 100 return result;
102 } 101 }
diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs
index 7518b86..309dab4 100644
--- a/OpenSim/Services/InventoryService/XInventoryService.cs
+++ b/OpenSim/Services/InventoryService/XInventoryService.cs
@@ -94,6 +94,7 @@ namespace OpenSim.Services.InventoryService
94 94
95 m_Database = LoadPlugin<IXInventoryData>(dllName, 95 m_Database = LoadPlugin<IXInventoryData>(dllName,
96 new Object[] {connString, String.Empty}); 96 new Object[] {connString, String.Empty});
97
97 if (m_Database == null) 98 if (m_Database == null)
98 throw new Exception("Could not find a storage interface in the given module"); 99 throw new Exception("Could not find a storage interface in the given module");
99 } 100 }
@@ -229,10 +230,28 @@ namespace OpenSim.Services.InventoryService
229 public virtual InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) 230 public virtual InventoryFolderBase GetFolderForType(UUID principalID, AssetType type)
230 { 231 {
231// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID); 232// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID);
233
234 InventoryFolderBase rootFolder = GetRootFolder(principalID);
235
236 if (rootFolder == null)
237 {
238 m_log.WarnFormat(
239 "[XINVENTORY]: Found no root folder for {0} in GetFolderForType() when looking for {1}",
240 principalID, type);
241
242 return null;
243 }
244
245 return GetSystemFolderForType(rootFolder, type);
246 }
247
248 private InventoryFolderBase GetSystemFolderForType(InventoryFolderBase rootFolder, AssetType type)
249 {
250// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID);
232 251
233 XInventoryFolder[] folders = m_Database.GetFolders( 252 XInventoryFolder[] folders = m_Database.GetFolders(
234 new string[] { "agentID", "type"}, 253 new string[] { "agentID", "parentFolderID", "type"},
235 new string[] { principalID.ToString(), ((int)type).ToString() }); 254 new string[] { rootFolder.Owner.ToString(), rootFolder.ID.ToString(), ((int)type).ToString() });
236 255
237 if (folders.Length == 0) 256 if (folders.Length == 0)
238 { 257 {
@@ -308,22 +327,38 @@ namespace OpenSim.Services.InventoryService
308 if (check != null) 327 if (check != null)
309 return false; 328 return false;
310 329
311 if (folder.Type == (short)AssetType.Folder 330 if (folder.Type != (short)AssetType.Folder && folder.Type != (short)AssetType.Unknown)
312 || folder.Type == (short)AssetType.Unknown
313 || folder.Type == (short)AssetType.OutfitFolder
314 || GetFolderForType(folder.Owner, (AssetType)(folder.Type)) == null)
315 { 331 {
316 XInventoryFolder xFolder = ConvertFromOpenSim(folder); 332 InventoryFolderBase rootFolder = GetRootFolder(folder.Owner);
317 return m_Database.StoreFolder(xFolder); 333
318 } 334 if (rootFolder == null)
319 else 335 {
320 { 336 m_log.WarnFormat(
321 m_log.WarnFormat( 337 "[XINVENTORY]: Found no root folder for {0} in AddFolder() when looking for {1}",
322 "[XINVENTORY]: Folder of type {0} already exists when tried to add {1} to {2} for {3}", 338 folder.Owner, folder.Type);
323 folder.Type, folder.Name, folder.ParentID, folder.Owner); 339
340 return false;
341 }
342
343 // Check we're not trying to add this as a system folder.
344 if (folder.ParentID == rootFolder.ID)
345 {
346 InventoryFolderBase existingSystemFolder
347 = GetSystemFolderForType(rootFolder, (AssetType)folder.Type);
348
349 if (existingSystemFolder != null)
350 {
351 m_log.WarnFormat(
352 "[XINVENTORY]: System folder of type {0} already exists when tried to add {1} to {2} for {3}",
353 folder.Type, folder.Name, folder.ParentID, folder.Owner);
354
355 return false;
356 }
357 }
324 } 358 }
325 359
326 return false; 360 XInventoryFolder xFolder = ConvertFromOpenSim(folder);
361 return m_Database.StoreFolder(xFolder);
327 } 362 }
328 363
329 public virtual bool UpdateFolder(InventoryFolderBase folder) 364 public virtual bool UpdateFolder(InventoryFolderBase folder)
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index 988a9b9..cbb6e6c 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -300,7 +300,7 @@ namespace OpenSim.Services.LLLoginService
300 { 300 {
301 m_log.InfoFormat( 301 m_log.InfoFormat(
302 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}", 302 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}",
303 firstName, lastName, m_MinLoginLevel, account.UserLevel); 303 firstName, lastName, account.UserLevel, m_MinLoginLevel);
304 return LLFailedLoginResponse.LoginBlockedProblem; 304 return LLFailedLoginResponse.LoginBlockedProblem;
305 } 305 }
306 306
diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs
index ac3d8fd..43fa04b 100644
--- a/OpenSim/Services/UserAccountService/GridUserService.cs
+++ b/OpenSim/Services/UserAccountService/GridUserService.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Services.UserAccountService
49 m_log.Debug("[USER GRID SERVICE]: Starting user grid service"); 49 m_log.Debug("[USER GRID SERVICE]: Starting user grid service");
50 } 50 }
51 51
52 public GridUserInfo GetGridUserInfo(string userID) 52 public virtual GridUserInfo GetGridUserInfo(string userID)
53 { 53 {
54 GridUserData d = m_Database.Get(userID); 54 GridUserData d = m_Database.Get(userID);
55 55
@@ -122,17 +122,6 @@ namespace OpenSim.Services.UserAccountService
122 return m_Database.Store(d); 122 return m_Database.Store(d);
123 } 123 }
124 124
125 protected bool StoreGridUserInfo(GridUserInfo info)
126 {
127 GridUserData d = new GridUserData();
128
129 d.Data["HomeRegionID"] = info.HomeRegionID.ToString();
130 d.Data["HomePosition"] = info.HomePosition.ToString();
131 d.Data["HomeLookAt"] = info.HomeLookAt.ToString();
132
133 return m_Database.Store(d);
134 }
135
136 public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt) 125 public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt)
137 { 126 {
138 GridUserData d = m_Database.Get(userID); 127 GridUserData d = m_Database.Get(userID);
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index 7598cc3..fc49169 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -245,7 +245,7 @@ namespace OpenSim.Tests.Common
245 config.AddConfig("Modules"); 245 config.AddConfig("Modules");
246 config.AddConfig("InventoryService"); 246 config.AddConfig("InventoryService");
247 config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector"); 247 config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector");
248 config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:InventoryService"); 248 config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:XInventoryService");
249 config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); 249 config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
250 250
251 LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); 251 LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector();
diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
index b3a7c9e..87d9410 100644
--- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs
@@ -199,7 +199,9 @@ namespace OpenSim.Tests.Common
199 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); 199 string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);
200 200
201 InventoryFolderBase newFolder 201 InventoryFolderBase newFolder
202 = new InventoryFolderBase(UUID.Random(), components[0], parentFolder.Owner, parentFolder.ID); 202 = new InventoryFolderBase(
203 UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0);
204
203 inventoryService.AddFolder(newFolder); 205 inventoryService.AddFolder(newFolder);
204 206
205 if (components.Length > 1) 207 if (components.Length > 1)
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 49a8d26..87ca944 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -939,12 +939,12 @@ namespace OpenSim.Tests.Common.Mock
939 Close(); 939 Close();
940 } 940 }
941 941
942 public void Close(bool c) 942 public void Close()
943 { 943 {
944 Close(); 944 Close(true, false);
945 } 945 }
946 946
947 public void Close() 947 public void Close(bool sendStop, bool force)
948 { 948 {
949 // Fire the callback for this connection closing 949 // Fire the callback for this connection closing
950 // This is necesary to get the presence detector to notice that a client has logged out. 950 // This is necesary to get the presence detector to notice that a client has logged out.
diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
new file mode 100644
index 0000000..bca5979
--- /dev/null
+++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
@@ -0,0 +1,131 @@
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.Linq;
31using System.Reflection;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Data;
36
37namespace OpenSim.Tests.Common.Mock
38{
39 public class TestXInventoryDataPlugin : IXInventoryData
40 {
41 private Dictionary<UUID, XInventoryFolder> m_allFolders = new Dictionary<UUID, XInventoryFolder>();
42 private Dictionary<UUID, XInventoryItem> m_allItems = new Dictionary<UUID, XInventoryItem>();
43
44 public TestXInventoryDataPlugin(string conn, string realm) {}
45
46 public XInventoryItem[] GetItems(string[] fields, string[] vals)
47 {
48 List<XInventoryItem> origItems = Get<XInventoryItem>(fields, vals, m_allItems.Values.ToList());
49
50 return origItems.Select(i => i.Clone()).ToArray();
51 }
52
53 public XInventoryFolder[] GetFolders(string[] fields, string[] vals)
54 {
55 List<XInventoryFolder> origFolders
56 = Get<XInventoryFolder>(fields, vals, m_allFolders.Values.ToList());
57
58 return origFolders.Select(f => f.Clone()).ToArray();
59 }
60
61 private List<T> Get<T>(string[] fields, string[] vals, List<T> inputEntities)
62 {
63 List<T> entities = inputEntities;
64
65 for (int i = 0; i < fields.Length; i++)
66 {
67 entities
68 = entities.Where(
69 e =>
70 {
71 FieldInfo fi = typeof(T).GetField(fields[i]);
72 if (fi == null)
73 throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i]));
74
75 return fi.GetValue(e).ToString() == vals[i];
76 }
77 ).ToList();
78 }
79
80 return entities;
81 }
82
83 public bool StoreFolder(XInventoryFolder folder)
84 {
85 m_allFolders[folder.folderID] = folder.Clone();
86
87// Console.WriteLine("Added folder {0} {1}", folder.folderName, folder.folderID);
88
89 return true;
90 }
91
92 public bool StoreItem(XInventoryItem item)
93 {
94 m_allItems[item.inventoryID] = item.Clone();
95
96// Console.WriteLine("Added item {0} {1}, creator {2}, owner {3}", item.inventoryName, item.inventoryID, item.creatorID, item.avatarID);
97
98 return true;
99 }
100
101 public bool DeleteFolders(string field, string val)
102 {
103 return DeleteFolders(new string[] { field }, new string[] { val });
104 }
105
106 public bool DeleteFolders(string[] fields, string[] vals)
107 {
108 XInventoryFolder[] foldersToDelete = GetFolders(fields, vals);
109 Array.ForEach(foldersToDelete, f => m_allFolders.Remove(f.folderID));
110
111 return true;
112 }
113
114 public bool DeleteItems(string field, string val)
115 {
116 return DeleteItems(new string[] { field }, new string[] { val });
117 }
118
119 public bool DeleteItems(string[] fields, string[] vals)
120 {
121 XInventoryItem[] itemsToDelete = GetItems(fields, vals);
122 Array.ForEach(itemsToDelete, i => m_allItems.Remove(i.inventoryID));
123
124 return true;
125 }
126
127 public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); }
128 public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); }
129 public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); }
130 }
131} \ No newline at end of file
diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs
index 30121fe..57da802 100644
--- a/OpenSim/Tests/Common/TestHelpers.cs
+++ b/OpenSim/Tests/Common/TestHelpers.cs
@@ -95,6 +95,7 @@ namespace OpenSim.Tests.Common
95 public static void EnableLogging() 95 public static void EnableLogging()
96 { 96 {
97 log4net.Config.XmlConfigurator.Configure(EnableLoggingConfigStream); 97 log4net.Config.XmlConfigurator.Configure(EnableLoggingConfigStream);
98 EnableLoggingConfigStream.Position = 0;
98 } 99 }
99 100
100 /// <summary> 101 /// <summary>
diff --git a/OpenSim/Tests/Torture/NPCTortureTests.cs b/OpenSim/Tests/Performance/NPCPerformanceTests.cs
index 731df68..627765b 100644
--- a/OpenSim/Tests/Torture/NPCTortureTests.cs
+++ b/OpenSim/Tests/Performance/NPCPerformanceTests.cs
@@ -47,10 +47,10 @@ using OpenSim.Services.AvatarService;
47using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock; 48using OpenSim.Tests.Common.Mock;
49 49
50namespace OpenSim.Tests.Torture 50namespace OpenSim.Tests.Performance
51{ 51{
52 /// <summary> 52 /// <summary>
53 /// NPC torture tests 53 /// NPC performance tests
54 /// </summary> 54 /// </summary>
55 /// <remarks> 55 /// <remarks>
56 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, 56 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached,
@@ -58,7 +58,7 @@ namespace OpenSim.Tests.Torture
58 /// earlier tests. 58 /// earlier tests.
59 /// </remarks> 59 /// </remarks>
60 [TestFixture] 60 [TestFixture]
61 public class NPCTortureTests 61 public class NPCPerformanceTests
62 { 62 {
63 private TestScene scene; 63 private TestScene scene;
64 private AvatarFactoryModule afm; 64 private AvatarFactoryModule afm;
diff --git a/OpenSim/Tests/Torture/ObjectTortureTests.cs b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs
index 195d47b..2264d86 100644
--- a/OpenSim/Tests/Torture/ObjectTortureTests.cs
+++ b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs
@@ -36,10 +36,10 @@ using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 36using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock; 37using OpenSim.Tests.Common.Mock;
38 38
39namespace OpenSim.Tests.Torture 39namespace OpenSim.Tests.Performance
40{ 40{
41 /// <summary> 41 /// <summary>
42 /// Object torture tests 42 /// Object performance tests
43 /// </summary> 43 /// </summary>
44 /// <remarks> 44 /// <remarks>
45 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, 45 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached,
@@ -47,7 +47,7 @@ namespace OpenSim.Tests.Torture
47 /// earlier tests. 47 /// earlier tests.
48 /// </remarks> 48 /// </remarks>
49 [TestFixture] 49 [TestFixture]
50 public class ObjectTortureTests 50 public class ObjectPerformanceTests
51 { 51 {
52 [TearDown] 52 [TearDown]
53 public void TearDown() 53 public void TearDown()
diff --git a/OpenSim/Tests/Torture/ScriptTortureTests.cs b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs
index 24f278f..d708abd 100644
--- a/OpenSim/Tests/Torture/ScriptTortureTests.cs
+++ b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs
@@ -42,10 +42,10 @@ using OpenSim.Region.ScriptEngine.XEngine;
42using OpenSim.Tests.Common; 42using OpenSim.Tests.Common;
43using OpenSim.Tests.Common.Mock; 43using OpenSim.Tests.Common.Mock;
44 44
45namespace OpenSim.Tests.Torture 45namespace OpenSim.Tests.Performance
46{ 46{
47 /// <summary> 47 /// <summary>
48 /// Script torture tests 48 /// Script performance tests
49 /// </summary> 49 /// </summary>
50 /// <remarks> 50 /// <remarks>
51 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, 51 /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached,
@@ -53,7 +53,7 @@ namespace OpenSim.Tests.Torture
53 /// earlier tests. 53 /// earlier tests.
54 /// </remarks> 54 /// </remarks>
55 [TestFixture] 55 [TestFixture]
56 public class ScriptTortureTests 56 public class ScriptPerformanceTests
57 { 57 {
58 private TestScene m_scene; 58 private TestScene m_scene;
59 private XEngine m_xEngine; 59 private XEngine m_xEngine;
diff --git a/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs
new file mode 100644
index 0000000..1f220c0
--- /dev/null
+++ b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs
@@ -0,0 +1,132 @@
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.IO;
31using System.Linq;
32using System.Reflection;
33using System.Threading;
34using log4net.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenMetaverse.Assets;
38using OpenSim.Framework;
39using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
40using OpenSim.Region.CoreModules.Scripting.VectorRender;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Scenes.Serialization;
43using OpenSim.Tests.Common;
44using OpenSim.Tests.Common.Mock;
45
46namespace OpenSim.Tests.Stress
47{
48 [TestFixture]
49 public class VectorRenderModuleStressTests : OpenSimTestCase
50 {
51 public Scene Scene { get; private set; }
52 public DynamicTextureModule Dtm { get; private set; }
53 public VectorRenderModule Vrm { get; private set; }
54
55 private void SetupScene(bool reuseTextures)
56 {
57 Scene = new SceneHelpers().SetupScene();
58
59 Dtm = new DynamicTextureModule();
60 Dtm.ReuseTextures = reuseTextures;
61
62 Vrm = new VectorRenderModule();
63
64 SceneHelpers.SetupSceneModules(Scene, Dtm, Vrm);
65 }
66
67 [Test]
68 public void TestConcurrentRepeatedDraw()
69 {
70 int threads = 4;
71 TestHelpers.InMethod();
72
73 SetupScene(false);
74
75 List<Drawer> drawers = new List<Drawer>();
76
77 for (int i = 0; i < threads; i++)
78 {
79 Drawer d = new Drawer(this, i);
80 drawers.Add(d);
81 Console.WriteLine("Starting drawer {0}", i);
82 Util.FireAndForget(o => d.Draw());
83 }
84
85 Thread.Sleep(10 * 60 * 1000);
86
87 drawers.ForEach(d => d.Ready = false);
88 drawers.ForEach(d => Console.WriteLine("Drawer {0} drew {1} textures", d.Number, d.Pass + 1));
89 }
90
91 class Drawer
92 {
93 public int Number { get; private set; }
94 public int Pass { get; private set; }
95 public bool Ready { get; set; }
96
97 private VectorRenderModuleStressTests m_tests;
98
99 public Drawer(VectorRenderModuleStressTests tests, int number)
100 {
101 m_tests = tests;
102 Number = number;
103 Ready = true;
104 }
105
106 public void Draw()
107 {
108 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_tests.Scene);
109
110 while (Ready)
111 {
112 UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
113
114 // Ensure unique text
115 string text = string.Format("{0:D2}{1}", Number, Pass);
116
117 m_tests.Dtm.AddDynamicTextureData(
118 m_tests.Scene.RegionInfo.RegionID,
119 so.UUID,
120 m_tests.Vrm.GetContentType(),
121 string.Format("PenColour BLACK; MoveTo 40,220; FontSize 32; Text {0};", text),
122 "",
123 0);
124
125 Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
126
127 Pass++;
128 }
129 }
130 }
131 }
132} \ No newline at end of file