aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs35
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs2
-rw-r--r--OpenSim/Data/IPresenceData.cs1
-rw-r--r--OpenSim/Data/IXGroupData.cs71
-rw-r--r--OpenSim/Data/MSSQL/MSSQLPresenceData.cs13
-rw-r--r--OpenSim/Data/MySQL/MySQLPresenceData.cs14
-rw-r--r--OpenSim/Data/Null/NullGenericDataHandler.cs67
-rw-r--r--OpenSim/Data/Null/NullPresenceData.cs8
-rw-r--r--OpenSim/Data/Null/NullXGroupData.cs90
-rw-r--r--OpenSim/Data/Tests/AssetTests.cs2
-rw-r--r--OpenSim/Data/Tests/BasicDataServiceTest.cs7
-rw-r--r--OpenSim/Data/Tests/PropertyCompareConstraint.cs3
-rw-r--r--OpenSim/Data/Tests/PropertyScrambler.cs3
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs28
-rw-r--r--OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs508
-rw-r--r--OpenSim/Framework/PluginManager.cs563
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs21
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs5
-rw-r--r--OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs2
-rw-r--r--OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs2
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs122
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs55
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs111
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs3
-rw-r--r--OpenSim/Framework/Servers/Tests/VersionInfoTests.cs3
-rw-r--r--OpenSim/Framework/Tests/AgentCircuitDataTest.cs5
-rw-r--r--OpenSim/Framework/Tests/AnimationTests.cs2
-rw-r--r--OpenSim/Framework/Tests/AssetBaseTest.cs3
-rw-r--r--OpenSim/Framework/Tests/CacheTests.cs3
-rw-r--r--OpenSim/Framework/Tests/LocationTest.cs3
-rw-r--r--OpenSim/Framework/Tests/MundaneFrameworkTests.cs11
-rw-r--r--OpenSim/Framework/Tests/PrimeNumberHelperTests.cs3
-rw-r--r--OpenSim/Framework/Tests/UtilTest.cs2
-rw-r--r--OpenSim/Framework/Util.cs24
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs138
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs38
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs25
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs11
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs317
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs107
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs13
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs60
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs3
-rw-r--r--OpenSim/Region/CoreModules/World/Wind/WindModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/EntityManager.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs22
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs18
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs36
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs101
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs83
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs43
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs15
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs127
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs82
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs97
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs987
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs28
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs283
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs200
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs324
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs37
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs272
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs110
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs114
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs156
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs45
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs203
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs278
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt204
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs4
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs13
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs9
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs26
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs5
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs3
-rw-r--r--OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs6
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs53
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs69
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs141
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs45
-rw-r--r--OpenSim/Server/Base/CommandManager.cs359
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs215
-rw-r--r--OpenSim/Server/Base/ServicesServerBase.cs10
-rw-r--r--OpenSim/Server/Handlers/Base/ServerConnector.cs67
-rw-r--r--OpenSim/Server/ServerMain.cs10
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs2
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs35
-rw-r--r--OpenSim/Services/Interfaces/IOfflineIMService.cs115
-rw-r--r--OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs77
-rw-r--r--OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs25
-rw-r--r--OpenSim/Tests/ConfigurationLoaderTest.cs3
-rw-r--r--OpenSim/Tests/Performance/NPCPerformanceTests.cs2
-rw-r--r--OpenSim/Tests/Performance/ObjectPerformanceTests.cs2
-rw-r--r--OpenSim/Tests/Performance/ScriptPerformanceTests.cs2
-rwxr-xr-xbin/Mono.Addins.CecilReflector.dllbin364032 -> 290816 bytes
-rwxr-xr-xbin/Mono.Addins.Setup.dllbin103424 -> 135168 bytes
-rwxr-xr-xbin/Mono.Addins.dllbin202752 -> 233472 bytes
-rw-r--r--bin/OpenMetaverse.dll.config2
-rwxr-xr-xbin/OpenSim.exe.config6
-rw-r--r--bin/OpenSimDefaults.ini46
-rw-r--r--bin/Robust.HG.ini.example13
-rw-r--r--bin/Robust.ini.example13
-rw-r--r--bin/config-include/GridCommon.ini.example5
-rwxr-xr-xbin/lib32/BulletSim.dllbin551424 -> 552960 bytes
-rwxr-xr-xbin/lib32/libBulletSim.sobin1707321 -> 1720874 bytes
-rwxr-xr-xbin/lib64/BulletSim.dllbin699904 -> 702464 bytes
-rwxr-xr-xbin/lib64/libBulletSim.sobin1844228 -> 1859487 bytes
-rw-r--r--prebuild.xml23
168 files changed, 6001 insertions, 2074 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index 6437d0b..822c50d 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -225,6 +225,11 @@ namespace OpenSim.Capabilities.Handlers
225 } 225 }
226 else 226 else
227 { 227 {
228 // Handle the case where no second range value was given. This is equivalent to requesting
229 // the rest of the entity.
230 if (end == -1)
231 end = int.MaxValue;
232
228 end = Utils.Clamp(end, 0, texture.Data.Length - 1); 233 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
229 start = Utils.Clamp(start, 0, end); 234 start = Utils.Clamp(start, 0, end);
230 int len = end - start + 1; 235 int len = end - start + 1;
@@ -283,15 +288,43 @@ namespace OpenSim.Capabilities.Handlers
283// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); 288// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
284 } 289 }
285 290
291 /// <summary>
292 /// Parse a range header.
293 /// </summary>
294 /// <remarks>
295 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
296 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
297 /// Where there is no value, -1 is returned.
298 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
299 /// for start.</remarks>
300 /// <returns></returns>
301 /// <param name='header'></param>
302 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
303 /// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
286 private bool TryParseRange(string header, out int start, out int end) 304 private bool TryParseRange(string header, out int start, out int end)
287 { 305 {
306 start = end = 0;
307
288 if (header.StartsWith("bytes=")) 308 if (header.StartsWith("bytes="))
289 { 309 {
290 string[] rangeValues = header.Substring(6).Split('-'); 310 string[] rangeValues = header.Substring(6).Split('-');
311
291 if (rangeValues.Length == 2) 312 if (rangeValues.Length == 2)
292 { 313 {
293 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) 314 if (!Int32.TryParse(rangeValues[0], out start))
315 return false;
316
317 string rawEnd = rangeValues[1];
318
319 if (rawEnd == "")
320 {
321 end = -1;
322 return true;
323 }
324 else if (Int32.TryParse(rawEnd, out end))
325 {
294 return true; 326 return true;
327 }
295 } 328 }
296 } 329 }
297 330
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
index b6ae41b..217a265 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock;
43namespace OpenSim.Capabilities.Handlers.GetTexture.Tests 43namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
44{ 44{
45 [TestFixture] 45 [TestFixture]
46 public class GetTextureHandlerTests 46 public class GetTextureHandlerTests : OpenSimTestCase
47 { 47 {
48 [Test] 48 [Test]
49 public void TestTextureNotFound() 49 public void TestTextureNotFound()
diff --git a/OpenSim/Data/IPresenceData.cs b/OpenSim/Data/IPresenceData.cs
index b871f56..9ec48b0 100644
--- a/OpenSim/Data/IPresenceData.cs
+++ b/OpenSim/Data/IPresenceData.cs
@@ -53,5 +53,6 @@ namespace OpenSim.Data
53 bool ReportAgent(UUID sessionID, UUID regionID); 53 bool ReportAgent(UUID sessionID, UUID regionID);
54 PresenceData[] Get(string field, string data); 54 PresenceData[] Get(string field, string data);
55 bool Delete(string field, string val); 55 bool Delete(string field, string val);
56 bool VerifyAgent(UUID agentId, UUID secureSessionID);
56 } 57 }
57} 58}
diff --git a/OpenSim/Data/IXGroupData.cs b/OpenSim/Data/IXGroupData.cs
new file mode 100644
index 0000000..2965e8c
--- /dev/null
+++ b/OpenSim/Data/IXGroupData.cs
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Data
34{
35 public class XGroup
36 {
37 public UUID groupID;
38 public UUID ownerRoleID;
39 public string name;
40 public string charter;
41 public bool showInList;
42 public UUID insigniaID;
43 public int membershipFee;
44 public bool openEnrollment;
45 public bool allowPublish;
46 public bool maturePublish;
47 public UUID founderID;
48 public ulong everyonePowers;
49 public ulong ownersPowers;
50
51 public XGroup Clone()
52 {
53 return (XGroup)MemberwiseClone();
54 }
55 }
56
57 /// <summary>
58 /// Early stub interface for groups data, not final.
59 /// </summary>
60 /// <remarks>
61 /// Currently in-use only for regression test purposes. Needs to be filled out over time.
62 /// </remarks>
63 public interface IXGroupData
64 {
65 bool StoreGroup(XGroup group);
66 XGroup[] GetGroups(string field, string val);
67 XGroup[] GetGroups(string[] fields, string[] vals);
68 bool DeleteGroups(string field, string val);
69 bool DeleteGroups(string[] fields, string[] vals);
70 }
71} \ No newline at end of file
diff --git a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs b/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
index e7b3d9c..deff2ed 100644
--- a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
@@ -100,5 +100,18 @@ namespace OpenSim.Data.MSSQL
100 return true; 100 return true;
101 } 101 }
102 102
103 public bool VerifyAgent(UUID agentId, UUID secureSessionID)
104 {
105 PresenceData[] ret = Get("SecureSessionID",
106 secureSessionID.ToString());
107
108 if (ret.Length == 0)
109 return false;
110
111 if(ret[0].UserID != agentId.ToString())
112 return false;
113
114 return true;
115 }
103 } 116 }
104} 117}
diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs
index 7808060..3f90639 100644
--- a/OpenSim/Data/MySQL/MySQLPresenceData.cs
+++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs
@@ -95,5 +95,19 @@ namespace OpenSim.Data.MySQL
95 95
96 return true; 96 return true;
97 } 97 }
98
99 public bool VerifyAgent(UUID agentId, UUID secureSessionID)
100 {
101 PresenceData[] ret = Get("SecureSessionID",
102 secureSessionID.ToString());
103
104 if (ret.Length == 0)
105 return false;
106
107 if(ret[0].UserID != agentId.ToString())
108 return false;
109
110 return true;
111 }
98 } 112 }
99} \ No newline at end of file 113} \ No newline at end of file
diff --git a/OpenSim/Data/Null/NullGenericDataHandler.cs b/OpenSim/Data/Null/NullGenericDataHandler.cs
new file mode 100644
index 0000000..dd9d190
--- /dev/null
+++ b/OpenSim/Data/Null/NullGenericDataHandler.cs
@@ -0,0 +1,67 @@
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.Data.Null
38{
39 /// <summary>
40 /// Not a proper generic data handler yet - probably needs to actually store the data as well instead of relying
41 /// on descendent classes
42 /// </summary>
43 public class NullGenericDataHandler
44 {
45 protected List<T> Get<T>(string[] fields, string[] vals, List<T> inputEntities)
46 {
47 List<T> entities = inputEntities;
48
49 for (int i = 0; i < fields.Length; i++)
50 {
51 entities
52 = entities.Where(
53 e =>
54 {
55 FieldInfo fi = typeof(T).GetField(fields[i]);
56 if (fi == null)
57 throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i]));
58
59 return fi.GetValue(e).ToString() == vals[i];
60 }
61 ).ToList();
62 }
63
64 return entities;
65 }
66 }
67} \ No newline at end of file
diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs
index c06c223..b85b95e 100644
--- a/OpenSim/Data/Null/NullPresenceData.cs
+++ b/OpenSim/Data/Null/NullPresenceData.cs
@@ -222,5 +222,13 @@ namespace OpenSim.Data.Null
222 return true; 222 return true;
223 } 223 }
224 224
225 public bool VerifyAgent(UUID agentId, UUID secureSessionID)
226 {
227 if (Instance != this)
228 return Instance.VerifyAgent(agentId, secureSessionID);
229
230 return false;
231 }
232
225 } 233 }
226} 234}
diff --git a/OpenSim/Data/Null/NullXGroupData.cs b/OpenSim/Data/Null/NullXGroupData.cs
new file mode 100644
index 0000000..7a86b9f
--- /dev/null
+++ b/OpenSim/Data/Null/NullXGroupData.cs
@@ -0,0 +1,90 @@
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;
30using System.Collections.Generic;
31using System.Linq;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Data;
38
39namespace OpenSim.Data.Null
40{
41 public class NullXGroupData : NullGenericDataHandler, IXGroupData
42 {
43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private Dictionary<UUID, XGroup> m_groups = new Dictionary<UUID, XGroup>();
46
47 public NullXGroupData(string connectionString, string realm) {}
48
49 public bool StoreGroup(XGroup group)
50 {
51 lock (m_groups)
52 {
53 m_groups[group.groupID] = group.Clone();
54 }
55
56 return true;
57 }
58
59 public XGroup[] GetGroups(string field, string val)
60 {
61 return GetGroups(new string[] { field }, new string[] { val });
62 }
63
64 public XGroup[] GetGroups(string[] fields, string[] vals)
65 {
66 lock (m_groups)
67 {
68 List<XGroup> origGroups = Get<XGroup>(fields, vals, m_groups.Values.ToList());
69
70 return origGroups.Select(g => g.Clone()).ToArray();
71 }
72 }
73
74 public bool DeleteGroups(string field, string val)
75 {
76 return DeleteGroups(new string[] { field }, new string[] { val });
77 }
78
79 public bool DeleteGroups(string[] fields, string[] vals)
80 {
81 lock (m_groups)
82 {
83 XGroup[] groupsToDelete = GetGroups(fields, vals);
84 Array.ForEach(groupsToDelete, g => m_groups.Remove(g.groupID));
85 }
86
87 return true;
88 }
89 }
90} \ No newline at end of file
diff --git a/OpenSim/Data/Tests/AssetTests.cs b/OpenSim/Data/Tests/AssetTests.cs
index 1174e2f..8cb2ee0 100644
--- a/OpenSim/Data/Tests/AssetTests.cs
+++ b/OpenSim/Data/Tests/AssetTests.cs
@@ -49,7 +49,7 @@ using OpenSim.Data.SQLite;
49namespace OpenSim.Data.Tests 49namespace OpenSim.Data.Tests
50{ 50{
51 [TestFixture(Description = "Asset store tests (SQLite)")] 51 [TestFixture(Description = "Asset store tests (SQLite)")]
52 public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData> 52 public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData>
53 { 53 {
54 } 54 }
55 55
diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs
index 7d85f0c..69b79bf 100644
--- a/OpenSim/Data/Tests/BasicDataServiceTest.cs
+++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs
@@ -33,6 +33,7 @@ using NUnit.Framework;
33using NUnit.Framework.Constraints; 33using NUnit.Framework.Constraints;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Tests.Common;
36using log4net; 37using log4net;
37using System.Data; 38using System.Data;
38using System.Data.Common; 39using System.Data.Common;
@@ -43,6 +44,12 @@ namespace OpenSim.Data.Tests
43 /// <summary>This is a base class for testing any Data service for any DBMS. 44 /// <summary>This is a base class for testing any Data service for any DBMS.
44 /// Requires NUnit 2.5 or better (to support the generics). 45 /// Requires NUnit 2.5 or better (to support the generics).
45 /// </summary> 46 /// </summary>
47 /// <remarks>
48 /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
49 /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
50 /// and similar on EstateTests, InventoryTests and RegionTests.
51 /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
52 /// </remarks>
46 /// <typeparam name="TConn"></typeparam> 53 /// <typeparam name="TConn"></typeparam>
47 /// <typeparam name="TService"></typeparam> 54 /// <typeparam name="TService"></typeparam>
48 public class BasicDataServiceTest<TConn, TService> 55 public class BasicDataServiceTest<TConn, TService>
diff --git a/OpenSim/Data/Tests/PropertyCompareConstraint.cs b/OpenSim/Data/Tests/PropertyCompareConstraint.cs
index 6c79bda..b99525a 100644
--- a/OpenSim/Data/Tests/PropertyCompareConstraint.cs
+++ b/OpenSim/Data/Tests/PropertyCompareConstraint.cs
@@ -36,6 +36,7 @@ using NUnit.Framework;
36using NUnit.Framework.Constraints; 36using NUnit.Framework.Constraints;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Tests.Common;
39 40
40namespace OpenSim.Data.Tests 41namespace OpenSim.Data.Tests
41{ 42{
@@ -254,7 +255,7 @@ namespace OpenSim.Data.Tests
254 } 255 }
255 256
256 [TestFixture] 257 [TestFixture]
257 public class PropertyCompareConstraintTest 258 public class PropertyCompareConstraintTest : OpenSimTestCase
258 { 259 {
259 public class HasInt 260 public class HasInt
260 { 261 {
diff --git a/OpenSim/Data/Tests/PropertyScrambler.cs b/OpenSim/Data/Tests/PropertyScrambler.cs
index c5d40c2..e0f5862 100644
--- a/OpenSim/Data/Tests/PropertyScrambler.cs
+++ b/OpenSim/Data/Tests/PropertyScrambler.cs
@@ -34,6 +34,7 @@ using System.Text;
34using NUnit.Framework; 34using NUnit.Framework;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Tests.Common;
37 38
38namespace OpenSim.Data.Tests 39namespace OpenSim.Data.Tests
39{ 40{
@@ -158,7 +159,7 @@ namespace OpenSim.Data.Tests
158 } 159 }
159 160
160 [TestFixture] 161 [TestFixture]
161 public class PropertyScramblerTests 162 public class PropertyScramblerTests : OpenSimTestCase
162 { 163 {
163 [Test] 164 [Test]
164 public void TestScramble() 165 public void TestScramble()
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index 16a63e0..dff956a 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -97,7 +97,7 @@ namespace OpenSim.Framework.Console
97 if (!UUID.TryParse(rawUuid, out uuid)) 97 if (!UUID.TryParse(rawUuid, out uuid))
98 { 98 {
99 if (console != null) 99 if (console != null)
100 console.OutputFormat("{0} is not a valid uuid", rawUuid); 100 console.OutputFormat("ERROR: {0} is not a valid uuid", rawUuid);
101 101
102 return false; 102 return false;
103 } 103 }
@@ -110,7 +110,7 @@ namespace OpenSim.Framework.Console
110 if (!uint.TryParse(rawLocalId, out localId)) 110 if (!uint.TryParse(rawLocalId, out localId))
111 { 111 {
112 if (console != null) 112 if (console != null)
113 console.OutputFormat("{0} is not a valid local id", localId); 113 console.OutputFormat("ERROR: {0} is not a valid local id", localId);
114 114
115 return false; 115 return false;
116 } 116 }
@@ -118,7 +118,7 @@ namespace OpenSim.Framework.Console
118 if (localId == 0) 118 if (localId == 0)
119 { 119 {
120 if (console != null) 120 if (console != null)
121 console.OutputFormat("{0} is not a valid local id - it must be greater than 0", localId); 121 console.OutputFormat("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
122 122
123 return false; 123 return false;
124 } 124 }
@@ -150,10 +150,30 @@ namespace OpenSim.Framework.Console
150 } 150 }
151 151
152 if (console != null) 152 if (console != null)
153 console.OutputFormat("{0} is not a valid UUID or local id", rawId); 153 console.OutputFormat("ERROR: {0} is not a valid UUID or local id", rawId);
154 154
155 return false; 155 return false;
156 } 156 }
157
158 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
160 /// </summary>
161 /// <param name='console'>Can be null if no console is available.</param>
162 /// <param name='rawConsoleVector'>/param>
163 /// <param name='vector'></param>
164 /// <returns></returns>
165 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
166 {
167 if (!int.TryParse(rawConsoleInt, out i))
168 {
169 if (console != null)
170 console.OutputFormat("ERROR: {0} is not a valid integer", rawConsoleInt);
171
172 return false;
173 }
174
175 return true;
176 }
157 177
158 /// <summary> 178 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 179 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
new file mode 100644
index 0000000..9056548
--- /dev/null
+++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
@@ -0,0 +1,508 @@
1/*
2 * Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27using System;
28using System.Threading;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework
32{
33 /// <summary>
34 /// A double dictionary that is thread abort safe.
35 /// </summary>
36 /// <remarks>
37 /// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
38 /// a finally section (which can't be interrupted by Thread.Abort()).
39 /// </remarks>
40 public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
41 {
42 Dictionary<TKey1, TValue> Dictionary1;
43 Dictionary<TKey2, TValue> Dictionary2;
44 ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
45
46 public DoubleDictionaryThreadAbortSafe()
47 {
48 Dictionary1 = new Dictionary<TKey1,TValue>();
49 Dictionary2 = new Dictionary<TKey2,TValue>();
50 }
51
52 public DoubleDictionaryThreadAbortSafe(int capacity)
53 {
54 Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
55 Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
56 }
57
58 public void Add(TKey1 key1, TKey2 key2, TValue value)
59 {
60 bool gotLock = false;
61
62 try
63 {
64 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
65 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
66 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
67 try {}
68 finally
69 {
70 rwLock.EnterWriteLock();
71 gotLock = true;
72 }
73
74 if (Dictionary1.ContainsKey(key1))
75 {
76 if (!Dictionary2.ContainsKey(key2))
77 throw new ArgumentException("key1 exists in the dictionary but not key2");
78 }
79 else if (Dictionary2.ContainsKey(key2))
80 {
81 if (!Dictionary1.ContainsKey(key1))
82 throw new ArgumentException("key2 exists in the dictionary but not key1");
83 }
84
85 Dictionary1[key1] = value;
86 Dictionary2[key2] = value;
87 }
88 finally
89 {
90 if (gotLock)
91 rwLock.ExitWriteLock();
92 }
93 }
94
95 public bool Remove(TKey1 key1, TKey2 key2)
96 {
97 bool success;
98 bool gotLock = false;
99
100 try
101 {
102 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
103 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
104 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
105 try {}
106 finally
107 {
108 rwLock.EnterWriteLock();
109 gotLock = true;
110 }
111
112 Dictionary1.Remove(key1);
113 success = Dictionary2.Remove(key2);
114 }
115 finally
116 {
117 if (gotLock)
118 rwLock.ExitWriteLock();
119 }
120
121 return success;
122 }
123
124 public bool Remove(TKey1 key1)
125 {
126 bool found = false;
127 bool gotLock = false;
128
129 try
130 {
131 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
132 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
133 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
134 try {}
135 finally
136 {
137 rwLock.EnterWriteLock();
138 gotLock = true;
139 }
140
141 // This is an O(n) operation!
142 TValue value;
143 if (Dictionary1.TryGetValue(key1, out value))
144 {
145 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
146 {
147 if (kvp.Value.Equals(value))
148 {
149 Dictionary1.Remove(key1);
150 Dictionary2.Remove(kvp.Key);
151 found = true;
152 break;
153 }
154 }
155 }
156 }
157 finally
158 {
159 if (gotLock)
160 rwLock.ExitWriteLock();
161 }
162
163 return found;
164 }
165
166 public bool Remove(TKey2 key2)
167 {
168 bool found = false;
169 bool gotLock = false;
170
171 try
172 {
173 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
174 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
175 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
176 try {}
177 finally
178 {
179 rwLock.EnterWriteLock();
180 gotLock = true;
181 }
182
183 // This is an O(n) operation!
184 TValue value;
185 if (Dictionary2.TryGetValue(key2, out value))
186 {
187 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
188 {
189 if (kvp.Value.Equals(value))
190 {
191 Dictionary2.Remove(key2);
192 Dictionary1.Remove(kvp.Key);
193 found = true;
194 break;
195 }
196 }
197 }
198 }
199 finally
200 {
201 if (gotLock)
202 rwLock.ExitWriteLock();
203 }
204
205 return found;
206 }
207
208 public void Clear()
209 {
210 bool gotLock = false;
211
212 try
213 {
214 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
215 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
216 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
217 try {}
218 finally
219 {
220 rwLock.EnterWriteLock();
221 gotLock = true;
222 }
223
224 Dictionary1.Clear();
225 Dictionary2.Clear();
226 }
227 finally
228 {
229 if (gotLock)
230 rwLock.ExitWriteLock();
231 }
232 }
233
234 public int Count
235 {
236 get { return Dictionary1.Count; }
237 }
238
239 public bool ContainsKey(TKey1 key)
240 {
241 return Dictionary1.ContainsKey(key);
242 }
243
244 public bool ContainsKey(TKey2 key)
245 {
246 return Dictionary2.ContainsKey(key);
247 }
248
249 public bool TryGetValue(TKey1 key, out TValue value)
250 {
251 bool success;
252 bool gotLock = false;
253
254 try
255 {
256 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
257 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
258 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
259 try {}
260 finally
261 {
262 rwLock.EnterReadLock();
263 gotLock = true;
264 }
265
266 success = Dictionary1.TryGetValue(key, out value);
267 }
268 finally
269 {
270 if (gotLock)
271 rwLock.ExitReadLock();
272 }
273
274 return success;
275 }
276
277 public bool TryGetValue(TKey2 key, out TValue value)
278 {
279 bool success;
280 bool gotLock = false;
281
282 try
283 {
284 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
285 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
286 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
287 try {}
288 finally
289 {
290 rwLock.EnterReadLock();
291 gotLock = true;
292 }
293
294 success = Dictionary2.TryGetValue(key, out value);
295 }
296 finally
297 {
298 if (gotLock)
299 rwLock.ExitReadLock();
300 }
301
302 return success;
303 }
304
305 public void ForEach(Action<TValue> action)
306 {
307 bool gotLock = false;
308
309 try
310 {
311 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
312 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
313 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
314 try {}
315 finally
316 {
317 rwLock.EnterReadLock();
318 gotLock = true;
319 }
320
321 foreach (TValue value in Dictionary1.Values)
322 action(value);
323 }
324 finally
325 {
326 if (gotLock)
327 rwLock.ExitReadLock();
328 }
329 }
330
331 public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
332 {
333 bool gotLock = false;
334
335 try
336 {
337 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
338 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
339 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
340 try {}
341 finally
342 {
343 rwLock.EnterReadLock();
344 gotLock = true;
345 }
346
347 foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
348 action(entry);
349 }
350 finally
351 {
352 if (gotLock)
353 rwLock.ExitReadLock();
354 }
355 }
356
357 public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
358 {
359 bool gotLock = false;
360
361 try
362 {
363 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
364 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
365 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
366 try {}
367 finally
368 {
369 rwLock.EnterReadLock();
370 gotLock = true;
371 }
372
373 foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
374 action(entry);
375 }
376 finally
377 {
378 if (gotLock)
379 rwLock.ExitReadLock();
380 }
381 }
382
383 public TValue FindValue(Predicate<TValue> predicate)
384 {
385 bool gotLock = false;
386
387 try
388 {
389 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
390 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
391 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
392 try {}
393 finally
394 {
395 rwLock.EnterReadLock();
396 gotLock = true;
397 }
398
399 foreach (TValue value in Dictionary1.Values)
400 {
401 if (predicate(value))
402 return value;
403 }
404 }
405 finally
406 {
407 if (gotLock)
408 rwLock.ExitReadLock();
409 }
410
411 return default(TValue);
412 }
413
414 public IList<TValue> FindAll(Predicate<TValue> predicate)
415 {
416 IList<TValue> list = new List<TValue>();
417 bool gotLock = false;
418
419 try
420 {
421 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
422 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
423 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
424 try {}
425 finally
426 {
427 rwLock.EnterReadLock();
428 gotLock = true;
429 }
430
431 foreach (TValue value in Dictionary1.Values)
432 {
433 if (predicate(value))
434 list.Add(value);
435 }
436 }
437 finally
438 {
439 if (gotLock)
440 rwLock.ExitReadLock();
441 }
442
443 return list;
444 }
445
446 public int RemoveAll(Predicate<TValue> predicate)
447 {
448 IList<TKey1> list = new List<TKey1>();
449 bool gotUpgradeableLock = false;
450
451 try
452 {
453 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
454 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
455 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
456 try {}
457 finally
458 {
459 rwLock.EnterUpgradeableReadLock();
460 gotUpgradeableLock = true;
461 }
462
463 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
464 {
465 if (predicate(kvp.Value))
466 list.Add(kvp.Key);
467 }
468
469 IList<TKey2> list2 = new List<TKey2>(list.Count);
470 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
471 {
472 if (predicate(kvp.Value))
473 list2.Add(kvp.Key);
474 }
475
476 bool gotWriteLock = false;
477
478 try
479 {
480 try {}
481 finally
482 {
483 rwLock.EnterUpgradeableReadLock();
484 gotWriteLock = true;
485 }
486
487 for (int i = 0; i < list.Count; i++)
488 Dictionary1.Remove(list[i]);
489
490 for (int i = 0; i < list2.Count; i++)
491 Dictionary2.Remove(list2[i]);
492 }
493 finally
494 {
495 if (gotWriteLock)
496 rwLock.ExitWriteLock();
497 }
498 }
499 finally
500 {
501 if (gotUpgradeableLock)
502 rwLock.ExitUpgradeableReadLock();
503 }
504
505 return list.Count;
506 }
507 }
508} \ No newline at end of file
diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs
new file mode 100644
index 0000000..00263f5
--- /dev/null
+++ b/OpenSim/Framework/PluginManager.cs
@@ -0,0 +1,563 @@
1
2/*
3 * Copyright (c) Contributors, http://opensimulator.org/
4 * See CONTRIBUTORS.TXT for a full list of copyright holders.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the OpenSimulator Project nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30using System;
31using System.Text;
32using System.Linq;
33using System.Collections;
34using System.Collections.Generic;
35using System.Collections.ObjectModel;
36using Mono.Addins;
37using Mono.Addins.Setup;
38using Mono.Addins.Description;
39using OpenSim.Framework;
40
41
42namespace OpenSim.Framework
43{
44 /// <summary>
45 /// Manager for registries and plugins
46 /// </summary>
47 public class PluginManager : SetupService
48 {
49 public AddinRegistry PluginRegistry;
50
51 public PluginManager(AddinRegistry registry): base (registry)
52 {
53 PluginRegistry = registry;
54
55 }
56
57 /// <summary>
58 /// Installs the plugin.
59 /// </summary>
60 /// <returns>
61 /// The plugin.
62 /// </returns>
63 /// <param name='args'>
64 /// Arguments.
65 /// </param>
66 public bool InstallPlugin(int ndx, out Dictionary<string, object> result)
67 {
68 Dictionary<string, object> res = new Dictionary<string, object>();
69
70 PackageCollection pack = new PackageCollection();
71 PackageCollection toUninstall;
72 DependencyCollection unresolved;
73
74 IProgressStatus ps = new ConsoleProgressStatus(false);
75
76 AddinRepositoryEntry[] available = GetSortedAvailbleAddins();
77
78 if (ndx > (available.Length - 1))
79 {
80 MainConsole.Instance.Output("Selection out of range");
81 result = res;
82 return false;
83 }
84
85 AddinRepositoryEntry aentry = available[ndx];
86
87 Package p = Package.FromRepository(aentry);
88 pack.Add(p);
89
90 ResolveDependencies(ps, pack, out toUninstall, out unresolved);
91
92 // Attempt to install the plugin disabled
93 if (Install(ps, pack) == true)
94 {
95 MainConsole.Instance.Output("Ignore the following error...");
96 PluginRegistry.Update(ps);
97 Addin addin = PluginRegistry.GetAddin(aentry.Addin.Id);
98 PluginRegistry.DisableAddin(addin.Id);
99 addin.Enabled = false;
100
101 MainConsole.Instance.Output("Installation Success");
102 ListInstalledAddins(out res);
103 result = res;
104 return true;
105 }
106 else
107 {
108 MainConsole.Instance.Output("Installation Failed");
109 result = res;
110 return false;
111 }
112 }
113
114 // Remove plugin
115 /// <summary>
116 /// Uns the install.
117 /// </summary>
118 /// <param name='args'>
119 /// Arguments.
120 /// </param>
121 public void UnInstall(int ndx)
122 {
123 Addin[] addins = GetSortedAddinList("RobustPlugin");
124
125 if (ndx > (addins.Length -1))
126 {
127 MainConsole.Instance.Output("Selection out of range");
128 return;
129 }
130
131 Addin addin = addins[ndx];
132 MainConsole.Instance.OutputFormat("Uninstalling plugin {0}", addin.Id);
133 AddinManager.Registry.DisableAddin(addin.Id);
134 addin.Enabled = false;
135 IProgressStatus ps = new ConsoleProgressStatus(false);
136 Uninstall(ps, addin.Id);
137 MainConsole.Instance.Output("Uninstall Success - restart to complete operation");
138 return;
139 }
140
141 /// <summary>
142 /// Checks the installed.
143 /// </summary>
144 /// <returns>
145 /// The installed.
146 /// </returns>
147 public string CheckInstalled()
148 {
149 return "CheckInstall";
150 }
151
152 /// <summary>
153 /// Lists the installed addins.
154 /// </summary>
155 /// <param name='result'>
156 /// Result.
157 /// </param>
158 public void ListInstalledAddins(out Dictionary<string, object> result)
159 {
160 Dictionary<string, object> res = new Dictionary<string, object>();
161
162 Addin[] addins = GetSortedAddinList("RobustPlugin");
163 if(addins.Count() < 1)
164 {
165 MainConsole.Instance.Output("Error!");
166 }
167 int count = 0;
168 foreach (Addin addin in addins)
169 {
170 Dictionary<string, object> r = new Dictionary<string, object>();
171 r["enabled"] = addin.Enabled == true ? true : false;
172 r["name"] = addin.LocalId;
173 r["version"] = addin.Version;
174
175 res.Add(count.ToString(), r);
176
177 count++;
178 }
179 result = res;
180 return;
181 }
182
183 // List compatible plugins in registered repositories
184 /// <summary>
185 /// Lists the available.
186 /// </summary>
187 /// <param name='result'>
188 /// Result.
189 /// </param>
190 public void ListAvailable(out Dictionary<string, object> result)
191 {
192 Dictionary<string, object> res = new Dictionary<string, object>();
193
194 AddinRepositoryEntry[] addins = GetSortedAvailbleAddins();
195
196 int count = 0;
197 foreach (AddinRepositoryEntry addin in addins)
198 {
199 Dictionary<string, object> r = new Dictionary<string, object>();
200 r["name"] = addin.Addin.Name;
201 r["version"] = addin.Addin.Version;
202 r["repository"] = addin.RepositoryName;
203
204 res.Add(count.ToString(), r);
205 count++;
206 }
207 result = res;
208 return;
209 }
210
211 // List available updates ** 1
212 /// <summary>
213 /// Lists the updates.
214 /// </summary>
215 public void ListUpdates()
216 {
217 IProgressStatus ps = new ConsoleProgressStatus(true);
218 Console.WriteLine ("Looking for updates...");
219 Repositories.UpdateAllRepositories (ps);
220 Console.WriteLine ("Available add-in updates:");
221 bool found = false;
222 AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
223
224 foreach (AddinRepositoryEntry entry in entries)
225 {
226 Console.WriteLine(String.Format("{0}",entry.Addin.Id));
227 }
228 }
229
230 // Sync to repositories
231 /// <summary>
232 /// Update this instance.
233 /// </summary>
234 public string Update()
235 {
236 IProgressStatus ps = new ConsoleProgressStatus(true);
237 Repositories.UpdateAllRepositories(ps);
238 return "Update";
239 }
240
241 // Register a repository
242 /// <summary>
243 /// Register a repository with our server.
244 /// </summary>
245 /// <returns>
246 /// result of the action
247 /// </returns>
248 /// <param name='repo'>
249 /// The URL of the repository we want to add
250 /// </param>
251 public bool AddRepository(string repo)
252 {
253 Repositories.RegisterRepository(null, repo, true);
254 PluginRegistry.Rebuild(null);
255
256 return true;
257 }
258
259 /// <summary>
260 /// Gets the repository.
261 /// </summary>
262 public void GetRepository()
263 {
264 Repositories.UpdateAllRepositories(new ConsoleProgressStatus(false));
265 }
266
267 // Remove a repository from the list
268 /// <summary>
269 /// Removes the repository.
270 /// </summary>
271 /// <param name='args'>
272 /// Arguments.
273 /// </param>
274 public void RemoveRepository(string[] args)
275 {
276 AddinRepository[] reps = Repositories.GetRepositories();
277 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
278 if (reps.Length == 0)
279 {
280 MainConsole.Instance.Output("No repositories have been registered.");
281 return;
282 }
283
284 int n = Convert.ToInt16(args[2]);
285 if (n > (reps.Length -1))
286 {
287 MainConsole.Instance.Output("Selection out of range");
288 return;
289 }
290
291 AddinRepository rep = reps[n];
292 Repositories.RemoveRepository(rep.Url);
293 return;
294 }
295
296 // Enable repository
297 /// <summary>
298 /// Enables the repository.
299 /// </summary>
300 /// <param name='args'>
301 /// Arguments.
302 /// </param>
303 public void EnableRepository(string[] args)
304 {
305 AddinRepository[] reps = Repositories.GetRepositories();
306 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
307 if (reps.Length == 0)
308 {
309 MainConsole.Instance.Output("No repositories have been registered.");
310 return;
311 }
312
313 int n = Convert.ToInt16(args[2]);
314 if (n > (reps.Length -1))
315 {
316 MainConsole.Instance.Output("Selection out of range");
317 return;
318 }
319
320 AddinRepository rep = reps[n];
321 Repositories.SetRepositoryEnabled(rep.Url, true);
322 return;
323 }
324
325 // Disable a repository
326 /// <summary>
327 /// Disables the repository.
328 /// </summary>
329 /// <param name='args'>
330 /// Arguments.
331 /// </param>
332 public void DisableRepository(string[] args)
333 {
334 AddinRepository[] reps = Repositories.GetRepositories();
335 Array.Sort(reps, (r1,r2) => r1.Title.CompareTo(r2.Title));
336 if (reps.Length == 0)
337 {
338 MainConsole.Instance.Output("No repositories have been registered.");
339 return;
340 }
341
342 int n = Convert.ToInt16(args[2]);
343 if (n > (reps.Length -1))
344 {
345 MainConsole.Instance.Output("Selection out of range");
346 return;
347 }
348
349 AddinRepository rep = reps[n];
350 Repositories.SetRepositoryEnabled(rep.Url, false);
351 return;
352 }
353
354 // List registered repositories
355 /// <summary>
356 /// Lists the repositories.
357 /// </summary>
358 /// <param name='result'>
359 /// Result.
360 /// </param>
361 public void ListRepositories(out Dictionary<string, object> result)
362 {
363 Dictionary<string, object> res = new Dictionary<string, object>();
364 result = res;
365
366 AddinRepository[] reps = GetSortedAddinRepo();
367 if (reps.Length == 0)
368 {
369 MainConsole.Instance.Output("No repositories have been registered.");
370 return;
371 }
372
373 int count = 0;
374 foreach (AddinRepository rep in reps)
375 {
376 Dictionary<string, object> r = new Dictionary<string, object>();
377 r["enabled"] = rep.Enabled == true ? true : false;
378 r["name"] = rep.Name;
379 r["url"] = rep.Url;
380
381 res.Add(count.ToString(), r);
382 count++;
383 }
384 return;
385 }
386
387 /// <summary>
388 /// Updates the registry.
389 /// </summary>
390 public void UpdateRegistry()
391 {
392 PluginRegistry.Update();
393 }
394
395 // Show plugin info
396 /// <summary>
397 /// Addins the info.
398 /// </summary>
399 /// <returns>
400 /// The info.
401 /// </returns>
402 /// <param name='args'>
403 /// Arguments.
404 /// </param>
405 public bool AddinInfo(int ndx, out Dictionary<string, object> result)
406 {
407 Dictionary<string, object> res = new Dictionary<string, object>();
408 result = res;
409
410 Addin[] addins = GetSortedAddinList("RobustPlugin");
411
412 if (ndx > (addins.Length - 1))
413 {
414 MainConsole.Instance.Output("Selection out of range");
415 return false;
416 }
417 // author category description
418 Addin addin = addins[ndx];
419
420 res["author"] = addin.Description.Author;
421 res["category"] = addin.Description.Category;
422 res["description"] = addin.Description.Description;
423 res["name"] = addin.Name;
424 res["url"] = addin.Description.Url;
425 res["file_name"] = addin.Description.FileName;
426
427 result = res;
428 return true;
429 }
430
431 // Disable a plugin
432 /// <summary>
433 /// Disables the plugin.
434 /// </summary>
435 /// <param name='args'>
436 /// Arguments.
437 /// </param>
438 public void DisablePlugin(string[] args)
439 {
440 Addin[] addins = GetSortedAddinList("RobustPlugin");
441
442 int n = Convert.ToInt16(args[2]);
443 if (n > (addins.Length -1))
444 {
445 MainConsole.Instance.Output("Selection out of range");
446 return;
447 }
448
449 Addin addin = addins[n];
450 AddinManager.Registry.DisableAddin(addin.Id);
451 addin.Enabled = false;
452 return;
453 }
454
455 // Enable plugin
456 /// <summary>
457 /// Enables the plugin.
458 /// </summary>
459 /// <param name='args'>
460 /// Arguments.
461 /// </param>
462 public void EnablePlugin(string[] args)
463 {
464 Addin[] addins = GetSortedAddinList("RobustPlugin");
465
466 int n = Convert.ToInt16(args[2]);
467 if (n > (addins.Length -1))
468 {
469 MainConsole.Instance.Output("Selection out of range");
470 return;
471 }
472
473 Addin addin = addins[n];
474
475 addin.Enabled = true;
476 AddinManager.Registry.EnableAddin(addin.Id);
477 // AddinManager.Registry.Update();
478 if(PluginRegistry.IsAddinEnabled(addin.Id))
479 {
480 ConsoleProgressStatus ps = new ConsoleProgressStatus(false);
481 if (!AddinManager.AddinEngine.IsAddinLoaded(addin.Id))
482 {
483 MainConsole.Instance.Output("Ignore the following error...");
484 AddinManager.Registry.Rebuild(ps);
485 AddinManager.AddinEngine.LoadAddin(ps, addin.Id);
486 }
487 }
488 else
489 {
490 MainConsole.Instance.OutputFormat("Not Enabled in this domain {0}", addin.Name);
491 }
492 return;
493 }
494
495
496
497 #region Util
498 private void Testing()
499 {
500 Addin[] list = Registry.GetAddins();
501
502 var addins = list.Where( a => a.Description.Category == "RobustPlugin");
503
504 foreach (Addin addin in addins)
505 {
506 MainConsole.Instance.OutputFormat("Addin {0}", addin.Name);
507 }
508 }
509
510 // These will let us deal with numbered lists instead
511 // of needing to type in the full ids
512 private AddinRepositoryEntry[] GetSortedAvailbleAddins()
513 {
514 ArrayList list = new ArrayList();
515 list.AddRange(Repositories.GetAvailableAddins());
516
517 AddinRepositoryEntry[] addins = list.ToArray(typeof(AddinRepositoryEntry)) as AddinRepositoryEntry[];
518
519 Array.Sort(addins,(r1,r2) => r1.Addin.Id.CompareTo(r2.Addin.Id));
520
521 return addins;
522 }
523
524 private AddinRepository[] GetSortedAddinRepo()
525 {
526 ArrayList list = new ArrayList();
527 list.AddRange(Repositories.GetRepositories());
528
529 AddinRepository[] repos = list.ToArray(typeof(AddinRepository)) as AddinRepository[];
530 Array.Sort (repos,(r1,r2) => r1.Name.CompareTo(r2.Name));
531
532 return repos;
533 }
534
535 private Addin[] GetSortedAddinList(string category)
536 {
537
538 ArrayList xlist = new ArrayList();
539 ArrayList list = new ArrayList();
540 try
541 {
542 list.AddRange(PluginRegistry.GetAddins());
543 }
544 catch(Exception e)
545 {
546 Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
547 return x;
548 }
549
550 foreach (Addin addin in list)
551 {
552 if (addin.Description.Category == category)
553 xlist.Add(addin);
554 }
555
556 Addin[] addins = xlist.ToArray(typeof(Addin)) as Addin[];
557 Array.Sort(addins,(r1,r2) => r1.Id.CompareTo(r2.Id));
558
559 return addins;
560 }
561 #endregion Util
562 }
563}
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index fcc9873..948c259 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -192,18 +192,7 @@ namespace OpenSim.Framework
192 192
193 public PrimitiveBaseShape() 193 public PrimitiveBaseShape()
194 { 194 {
195 PCode = (byte) PCodeEnum.Primitive;
196 ExtraParams = new byte[1];
197 m_textureEntry = DEFAULT_TEXTURE;
198 }
199
200 public PrimitiveBaseShape(bool noShape)
201 {
202 if (noShape)
203 return;
204
205 PCode = (byte)PCodeEnum.Primitive; 195 PCode = (byte)PCodeEnum.Primitive;
206 ExtraParams = new byte[1];
207 m_textureEntry = DEFAULT_TEXTURE; 196 m_textureEntry = DEFAULT_TEXTURE;
208 } 197 }
209 198
@@ -216,7 +205,6 @@ namespace OpenSim.Framework
216// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID); 205// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
217 206
218 PCode = (byte)prim.PrimData.PCode; 207 PCode = (byte)prim.PrimData.PCode;
219 ExtraParams = new byte[1];
220 208
221 State = prim.PrimData.State; 209 State = prim.PrimData.State;
222 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); 210 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
@@ -248,7 +236,10 @@ namespace OpenSim.Framework
248 SculptTexture = prim.Sculpt.SculptTexture; 236 SculptTexture = prim.Sculpt.SculptTexture;
249 SculptType = (byte)prim.Sculpt.Type; 237 SculptType = (byte)prim.Sculpt.Type;
250 } 238 }
251 else SculptType = (byte)OpenMetaverse.SculptType.None; 239 else
240 {
241 SculptType = (byte)OpenMetaverse.SculptType.None;
242 }
252 } 243 }
253 244
254 [XmlIgnore] 245 [XmlIgnore]
@@ -340,9 +331,9 @@ namespace OpenSim.Framework
340 _scale = new Vector3(side, side, side); 331 _scale = new Vector3(side, side, side);
341 } 332 }
342 333
343 public void SetHeigth(float heigth) 334 public void SetHeigth(float height)
344 { 335 {
345 _scale.Z = heigth; 336 _scale.Z = height;
346 } 337 }
347 338
348 public void SetRadius(float radius) 339 public void SetRadius(float radius)
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 48f1c4f..0c12787 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -154,6 +154,11 @@ namespace OpenSim.Framework.Serialization
154 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; 154 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
155 } 155 }
156 156
157 public static string CreateOarLandDataPath(LandData ld)
158 {
159 return string.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, ld.GlobalID);
160 }
161
157 /// <summary> 162 /// <summary>
158 /// Create the filename used to store an object in an OpenSim Archive. 163 /// Create the filename used to store an object in an OpenSim Archive.
159 /// </summary> 164 /// </summary>
diff --git a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
index 8b9756b..ea100ee 100644
--- a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
+++ b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
37namespace OpenSim.Framework.Serialization.Tests 37namespace OpenSim.Framework.Serialization.Tests
38{ 38{
39 [TestFixture] 39 [TestFixture]
40 public class LandDataSerializerTest 40 public class LandDataSerializerTest : OpenSimTestCase
41 { 41 {
42 private LandData land; 42 private LandData land;
43 private LandData landWithParcelAccessList; 43 private LandData landWithParcelAccessList;
diff --git a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
index 09b6f6d..142726b 100644
--- a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
+++ b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
37namespace OpenSim.Framework.Serialization.Tests 37namespace OpenSim.Framework.Serialization.Tests
38{ 38{
39 [TestFixture] 39 [TestFixture]
40 public class RegionSettingsSerializerTests 40 public class RegionSettingsSerializerTests : OpenSimTestCase
41 { 41 {
42 private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?> 42 private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?>
43<RegionSettings> 43<RegionSettings>
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 2c21800..cb47cbf 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -27,7 +27,6 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
31using System.IO; 30using System.IO;
32using System.Reflection; 31using System.Reflection;
33using System.Text; 32using System.Text;
@@ -99,34 +98,6 @@ namespace OpenSim.Framework.Servers
99 m_console.Commands.AddCommand("General", false, "shutdown", 98 m_console.Commands.AddCommand("General", false, "shutdown",
100 "shutdown", 99 "shutdown",
101 "Quit the application", HandleQuit); 100 "Quit the application", HandleQuit);
102
103 m_console.Commands.AddCommand("General", false, "show threads",
104 "show threads",
105 "Show thread status", HandleShow);
106
107 m_console.Commands.AddCommand("General", false, "show version",
108 "show version",
109 "Show server version", HandleShow);
110
111 m_console.Commands.AddCommand("General", false, "threads abort",
112 "threads abort <thread-id>",
113 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
114
115 m_console.Commands.AddCommand("General", false, "threads show",
116 "threads show",
117 "Show thread status. Synonym for \"show threads\"",
118 (string module, string[] args) => Notice(GetThreadsReport()));
119
120 m_console.Commands.AddCommand("General", false, "force gc",
121 "force gc",
122 "Manually invoke runtime garbage collection. For debugging purposes",
123 HandleForceGc);
124 }
125
126 private void HandleForceGc(string module, string[] args)
127 {
128 MainConsole.Instance.Output("Manually invoking runtime garbage collection");
129 GC.Collect();
130 } 101 }
131 102
132 /// <summary> 103 /// <summary>
@@ -159,54 +130,6 @@ namespace OpenSim.Framework.Servers
159 } 130 }
160 131
161 /// <summary> 132 /// <summary>
162 /// Get a report about the registered threads in this server.
163 /// </summary>
164 protected string GetThreadsReport()
165 {
166 // This should be a constant field.
167 string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
168
169 StringBuilder sb = new StringBuilder();
170 Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
171
172 sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
173
174 int timeNow = Environment.TickCount & Int32.MaxValue;
175
176 sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
177 sb.Append(Environment.NewLine);
178
179 foreach (Watchdog.ThreadWatchdogInfo twi in threads)
180 {
181 Thread t = twi.Thread;
182
183 sb.AppendFormat(
184 reportFormat,
185 t.ManagedThreadId,
186 t.Name,
187 timeNow - twi.LastTick,
188 timeNow - twi.FirstTick,
189 t.Priority,
190 t.ThreadState);
191
192 sb.Append("\n");
193 }
194
195 sb.Append("\n");
196
197 // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
198 // zero active threads.
199 int totalThreads = Process.GetCurrentProcess().Threads.Count;
200 if (totalThreads > 0)
201 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
202
203 sb.Append("Main threadpool (excluding script engine pools)\n");
204 sb.Append(Util.GetThreadPoolReport());
205
206 return sb.ToString();
207 }
208
209 /// <summary>
210 /// Performs initialisation of the scene, such as loading configuration from disk. 133 /// Performs initialisation of the scene, such as loading configuration from disk.
211 /// </summary> 134 /// </summary>
212 public virtual void Startup() 135 public virtual void Startup()
@@ -246,50 +169,7 @@ namespace OpenSim.Framework.Servers
246 private void HandleQuit(string module, string[] args) 169 private void HandleQuit(string module, string[] args)
247 { 170 {
248 Shutdown(); 171 Shutdown();
249 } 172 }
250
251 public override void HandleShow(string module, string[] cmd)
252 {
253 base.HandleShow(module, cmd);
254
255 List<string> args = new List<string>(cmd);
256
257 args.RemoveAt(0);
258
259 string[] showParams = args.ToArray();
260
261 switch (showParams[0])
262 {
263 case "threads":
264 Notice(GetThreadsReport());
265 break;
266
267 case "version":
268 Notice(GetVersionText());
269 break;
270 }
271 }
272
273 public virtual void HandleThreadsAbort(string module, string[] cmd)
274 {
275 if (cmd.Length != 3)
276 {
277 MainConsole.Instance.Output("Usage: threads abort <thread-id>");
278 return;
279 }
280
281 int threadId;
282 if (!int.TryParse(cmd[2], out threadId))
283 {
284 MainConsole.Instance.Output("ERROR: Thread id must be an integer");
285 return;
286 }
287
288 if (Watchdog.AbortThread(threadId))
289 MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
290 else
291 MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
292 }
293 173
294 public string osSecret { 174 public string osSecret {
295 // Secret uuid for the simulator 175 // Secret uuid for the simulator
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 77fce9e..eefcdad 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -437,7 +437,7 @@ namespace OpenSim.Framework.Servers.HttpServer
437// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); 437// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
438 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); 438 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
439 439
440 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 440 Culture.SetCurrentCulture();
441 441
442// // 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
443// // 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
@@ -1283,59 +1283,6 @@ namespace OpenSim.Framework.Servers.HttpServer
1283 map["login"] = OSD.FromString("false"); 1283 map["login"] = OSD.FromString("false");
1284 return map; 1284 return map;
1285 } 1285 }
1286 /// <summary>
1287 /// A specific agent handler was provided. Such a handler is expecetd to have an
1288 /// intimate, and highly specific relationship with the client. Consequently,
1289 /// nothing is done here.
1290 /// </summary>
1291 /// <param name="handler"></param>
1292 /// <param name="request"></param>
1293 /// <param name="response"></param>
1294
1295 private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response)
1296 {
1297 // In the case of REST, then handler is responsible for ALL aspects of
1298 // the request/response handling. Nothing is done here, not even encoding.
1299
1300 try
1301 {
1302 return handler.Handle(request, response);
1303 }
1304 catch (Exception e)
1305 {
1306 // If the handler did in fact close the stream, then this will blow
1307 // chunks. So that that doesn't disturb anybody we throw away any
1308 // and all exceptions raised. We've done our best to release the
1309 // client.
1310 try
1311 {
1312 m_log.Warn("[HTTP-AGENT]: Error - " + e.Message);
1313 response.SendChunked = false;
1314 response.KeepAlive = true;
1315 response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError;
1316 //response.OutputStream.Close();
1317 try
1318 {
1319 response.Send();
1320 //response.FreeContext();
1321 }
1322 catch (SocketException f)
1323 {
1324 // This has to be here to prevent a Linux/Mono crash
1325 m_log.Warn(
1326 String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f);
1327 }
1328 }
1329 catch(Exception)
1330 {
1331 }
1332 }
1333
1334 // Indicate that the request has been "handled"
1335
1336 return true;
1337
1338 }
1339 1286
1340 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) 1287 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
1341 { 1288 {
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index c182a3a..47baac8 100644
--- a/OpenSim/Framework/Servers/ServerBase.cs
+++ b/OpenSim/Framework/Servers/ServerBase.cs
@@ -27,16 +27,19 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
30using System.IO; 31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Text; 33using System.Text;
33using System.Text.RegularExpressions; 34using System.Text.RegularExpressions;
35using System.Threading;
34using log4net; 36using log4net;
35using log4net.Appender; 37using log4net.Appender;
36using log4net.Core; 38using log4net.Core;
37using log4net.Repository; 39using log4net.Repository;
38using Nini.Config; 40using Nini.Config;
39using OpenSim.Framework.Console; 41using OpenSim.Framework.Console;
42using OpenSim.Framework.Monitoring;
40 43
41namespace OpenSim.Framework.Servers 44namespace OpenSim.Framework.Servers
42{ 45{
@@ -168,6 +171,9 @@ namespace OpenSim.Framework.Servers
168 "General", false, "show info", "show info", "Show general information about the server", HandleShow); 171 "General", false, "show info", "show info", "Show general information about the server", HandleShow);
169 172
170 m_console.Commands.AddCommand( 173 m_console.Commands.AddCommand(
174 "General", false, "show version", "show version", "Show server version", HandleShow);
175
176 m_console.Commands.AddCommand(
171 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); 177 "General", false, "show uptime", "show uptime", "Show server uptime", HandleShow);
172 178
173 m_console.Commands.AddCommand( 179 m_console.Commands.AddCommand(
@@ -206,6 +212,34 @@ namespace OpenSim.Framework.Servers
206 "General", false, "command-script", 212 "General", false, "command-script",
207 "command-script <script>", 213 "command-script <script>",
208 "Run a command script from file", HandleScript); 214 "Run a command script from file", HandleScript);
215
216 m_console.Commands.AddCommand(
217 "General", false, "show threads",
218 "show threads",
219 "Show thread status", HandleShow);
220
221 m_console.Commands.AddCommand(
222 "General", false, "threads abort",
223 "threads abort <thread-id>",
224 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
225
226 m_console.Commands.AddCommand(
227 "General", false, "threads show",
228 "threads show",
229 "Show thread status. Synonym for \"show threads\"",
230 (string module, string[] args) => Notice(GetThreadsReport()));
231
232 m_console.Commands.AddCommand(
233 "General", false, "force gc",
234 "force gc",
235 "Manually invoke runtime garbage collection. For debugging purposes",
236 HandleForceGc);
237 }
238
239 private void HandleForceGc(string module, string[] args)
240 {
241 Notice("Manually invoking runtime garbage collection");
242 GC.Collect();
209 } 243 }
210 244
211 public virtual void HandleShow(string module, string[] cmd) 245 public virtual void HandleShow(string module, string[] cmd)
@@ -222,9 +256,17 @@ namespace OpenSim.Framework.Servers
222 ShowInfo(); 256 ShowInfo();
223 break; 257 break;
224 258
259 case "version":
260 Notice(GetVersionText());
261 break;
262
225 case "uptime": 263 case "uptime":
226 Notice(GetUptimeReport()); 264 Notice(GetUptimeReport());
227 break; 265 break;
266
267 case "threads":
268 Notice(GetThreadsReport());
269 break;
228 } 270 }
229 } 271 }
230 272
@@ -537,6 +579,75 @@ namespace OpenSim.Framework.Servers
537 } 579 }
538 580
539 /// <summary> 581 /// <summary>
582 /// Get a report about the registered threads in this server.
583 /// </summary>
584 protected string GetThreadsReport()
585 {
586 // This should be a constant field.
587 string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
588
589 StringBuilder sb = new StringBuilder();
590 Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
591
592 sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
593
594 int timeNow = Environment.TickCount & Int32.MaxValue;
595
596 sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
597 sb.Append(Environment.NewLine);
598
599 foreach (Watchdog.ThreadWatchdogInfo twi in threads)
600 {
601 Thread t = twi.Thread;
602
603 sb.AppendFormat(
604 reportFormat,
605 t.ManagedThreadId,
606 t.Name,
607 timeNow - twi.LastTick,
608 timeNow - twi.FirstTick,
609 t.Priority,
610 t.ThreadState);
611
612 sb.Append("\n");
613 }
614
615 sb.Append("\n");
616
617 // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
618 // zero active threads.
619 int totalThreads = Process.GetCurrentProcess().Threads.Count;
620 if (totalThreads > 0)
621 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
622
623 sb.Append("Main threadpool (excluding script engine pools)\n");
624 sb.Append(Util.GetThreadPoolReport());
625
626 return sb.ToString();
627 }
628
629 public virtual void HandleThreadsAbort(string module, string[] cmd)
630 {
631 if (cmd.Length != 3)
632 {
633 MainConsole.Instance.Output("Usage: threads abort <thread-id>");
634 return;
635 }
636
637 int threadId;
638 if (!int.TryParse(cmd[2], out threadId))
639 {
640 MainConsole.Instance.Output("ERROR: Thread id must be an integer");
641 return;
642 }
643
644 if (Watchdog.AbortThread(threadId))
645 MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
646 else
647 MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
648 }
649
650 /// <summary>
540 /// Console output is only possible if a console has been established. 651 /// Console output is only possible if a console has been established.
541 /// That is something that cannot be determined within this class. So 652 /// That is something that cannot be determined within this class. So
542 /// all attempts to use the console MUST be verified. 653 /// all attempts to use the console MUST be verified.
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index 4c2f586..50f306e 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -35,11 +35,12 @@ using HttpServer;
35using HttpServer.FormDecoders; 35using HttpServer.FormDecoders;
36using NUnit.Framework; 36using NUnit.Framework;
37using OpenSim.Framework.Servers.HttpServer; 37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Tests.Common;
38 39
39namespace OpenSim.Framework.Servers.Tests 40namespace OpenSim.Framework.Servers.Tests
40{ 41{
41 [TestFixture] 42 [TestFixture]
42 public class OSHttpTests 43 public class OSHttpTests : OpenSimTestCase
43 { 44 {
44 // we need an IHttpClientContext for our tests 45 // we need an IHttpClientContext for our tests
45 public class TestHttpClientContext: IHttpClientContext 46 public class TestHttpClientContext: IHttpClientContext
diff --git a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
index 49e5061..480f2bb 100644
--- a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
+++ b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
@@ -29,11 +29,12 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenSim.Tests.Common;
32 33
33namespace OpenSim.Framework.Servers.Tests 34namespace OpenSim.Framework.Servers.Tests
34{ 35{
35 [TestFixture] 36 [TestFixture]
36 public class VersionInfoTests 37 public class VersionInfoTests : OpenSimTestCase
37 { 38 {
38 [Test] 39 [Test]
39 public void TestVersionLength() 40 public void TestVersionLength()
diff --git a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
index 0dce414..95e9439 100644
--- a/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
+++ b/OpenSim/Framework/Tests/AgentCircuitDataTest.cs
@@ -24,16 +24,17 @@
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
27using System.Collections.Generic; 28using System.Collections.Generic;
28using OpenMetaverse; 29using OpenMetaverse;
29using OpenMetaverse.StructuredData; 30using OpenMetaverse.StructuredData;
30using NUnit.Framework; 31using NUnit.Framework;
31 32using OpenSim.Tests.Common;
32 33
33namespace OpenSim.Framework.Tests 34namespace OpenSim.Framework.Tests
34{ 35{
35 [TestFixture] 36 [TestFixture]
36 public class AgentCircuitDataTest 37 public class AgentCircuitDataTest : OpenSimTestCase
37 { 38 {
38 private UUID AgentId; 39 private UUID AgentId;
39 private AvatarAppearance AvAppearance; 40 private AvatarAppearance AvAppearance;
diff --git a/OpenSim/Framework/Tests/AnimationTests.cs b/OpenSim/Framework/Tests/AnimationTests.cs
index 967a355..f3be81b 100644
--- a/OpenSim/Framework/Tests/AnimationTests.cs
+++ b/OpenSim/Framework/Tests/AnimationTests.cs
@@ -38,7 +38,7 @@ using Animation = OpenSim.Framework.Animation;
38namespace OpenSim.Framework.Tests 38namespace OpenSim.Framework.Tests
39{ 39{
40 [TestFixture] 40 [TestFixture]
41 public class AnimationTests 41 public class AnimationTests : OpenSimTestCase
42 { 42 {
43 private Animation anim1 = null; 43 private Animation anim1 = null;
44 private Animation anim2 = null; 44 private Animation anim2 = null;
diff --git a/OpenSim/Framework/Tests/AssetBaseTest.cs b/OpenSim/Framework/Tests/AssetBaseTest.cs
index 6db1aa0..25d2393 100644
--- a/OpenSim/Framework/Tests/AssetBaseTest.cs
+++ b/OpenSim/Framework/Tests/AssetBaseTest.cs
@@ -30,11 +30,12 @@ using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Tests.Common;
33 34
34namespace OpenSim.Framework.Tests 35namespace OpenSim.Framework.Tests
35{ 36{
36 [TestFixture] 37 [TestFixture]
37 public class AssetBaseTest 38 public class AssetBaseTest : OpenSimTestCase
38 { 39 {
39 [Test] 40 [Test]
40 public void TestContainsReferences() 41 public void TestContainsReferences()
diff --git a/OpenSim/Framework/Tests/CacheTests.cs b/OpenSim/Framework/Tests/CacheTests.cs
index c3613e6..c709860 100644
--- a/OpenSim/Framework/Tests/CacheTests.cs
+++ b/OpenSim/Framework/Tests/CacheTests.cs
@@ -28,11 +28,12 @@
28using System; 28using System;
29using NUnit.Framework; 29using NUnit.Framework;
30using OpenMetaverse; 30using OpenMetaverse;
31using OpenSim.Tests.Common;
31 32
32namespace OpenSim.Framework.Tests 33namespace OpenSim.Framework.Tests
33{ 34{
34 [TestFixture] 35 [TestFixture]
35 public class CacheTests 36 public class CacheTests : OpenSimTestCase
36 { 37 {
37 private Cache cache; 38 private Cache cache;
38 private UUID cacheItemUUID; 39 private UUID cacheItemUUID;
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs
index 2707afa..a56ecb4 100644
--- a/OpenSim/Framework/Tests/LocationTest.cs
+++ b/OpenSim/Framework/Tests/LocationTest.cs
@@ -26,11 +26,12 @@
26 */ 26 */
27 27
28using NUnit.Framework; 28using NUnit.Framework;
29using OpenSim.Tests.Common;
29 30
30namespace OpenSim.Framework.Tests 31namespace OpenSim.Framework.Tests
31{ 32{
32 [TestFixture] 33 [TestFixture]
33 public class LocationTest 34 public class LocationTest : OpenSimTestCase
34 { 35 {
35 [Test] 36 [Test]
36 public void locationRegionHandleRegionHandle() 37 public void locationRegionHandleRegionHandle()
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
index 6fde488..0fbdaf3 100644
--- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
+++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
@@ -32,11 +32,12 @@ using OpenMetaverse.StructuredData;
32using System; 32using System;
33using System.Globalization; 33using System.Globalization;
34using System.Threading; 34using System.Threading;
35using OpenSim.Tests.Common;
35 36
36namespace OpenSim.Framework.Tests 37namespace OpenSim.Framework.Tests
37{ 38{
38 [TestFixture] 39 [TestFixture]
39 public class MundaneFrameworkTests 40 public class MundaneFrameworkTests : OpenSimTestCase
40 { 41 {
41 private bool m_RegionSettingsOnSaveEventFired; 42 private bool m_RegionSettingsOnSaveEventFired;
42 private bool m_RegionLightShareDataOnSaveEventFired; 43 private bool m_RegionLightShareDataOnSaveEventFired;
@@ -302,10 +303,6 @@ namespace OpenSim.Framework.Tests
302 Culture.SetCurrentCulture(); 303 Culture.SetCurrentCulture();
303 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); 304 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
304 305
305 } 306 }
306
307
308
309 } 307 }
310} 308} \ No newline at end of file
311
diff --git a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
index 36bc6e7..82e13e5 100644
--- a/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
+++ b/OpenSim/Framework/Tests/PrimeNumberHelperTests.cs
@@ -31,11 +31,12 @@ using NUnit.Framework;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.StructuredData; 32using OpenMetaverse.StructuredData;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Tests.Common;
34 35
35namespace OpenSim.Framework.Tests 36namespace OpenSim.Framework.Tests
36{ 37{
37 [TestFixture] 38 [TestFixture]
38 public class PrimeNumberHelperTests 39 public class PrimeNumberHelperTests : OpenSimTestCase
39 { 40 {
40 [Test] 41 [Test]
41 public void TestGetPrime() 42 public void TestGetPrime()
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs
index f0d2a3f..11ca068 100644
--- a/OpenSim/Framework/Tests/UtilTest.cs
+++ b/OpenSim/Framework/Tests/UtilTest.cs
@@ -33,7 +33,7 @@ using OpenSim.Tests.Common;
33namespace OpenSim.Framework.Tests 33namespace OpenSim.Framework.Tests
34{ 34{
35 [TestFixture] 35 [TestFixture]
36 public class UtilTests 36 public class UtilTests : OpenSimTestCase
37 { 37 {
38 [Test] 38 [Test]
39 public void VectorOperationTests() 39 public void VectorOperationTests()
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index e76a37b..d206fc1 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1753,12 +1753,16 @@ namespace OpenSim.Framework
1753 StringBuilder sb = new StringBuilder(); 1753 StringBuilder sb = new StringBuilder();
1754 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 1754 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1755 { 1755 {
1756 threadPoolUsed = "SmartThreadPool"; 1756 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
1757 maxThreads = m_ThreadPool.MaxThreads; 1757 if (m_ThreadPool != null)
1758 minThreads = m_ThreadPool.MinThreads; 1758 {
1759 inUseThreads = m_ThreadPool.InUseThreads; 1759 threadPoolUsed = "SmartThreadPool";
1760 allocatedThreads = m_ThreadPool.ActiveThreads; 1760 maxThreads = m_ThreadPool.MaxThreads;
1761 waitingCallbacks = m_ThreadPool.WaitingCallbacks; 1761 minThreads = m_ThreadPool.MinThreads;
1762 inUseThreads = m_ThreadPool.InUseThreads;
1763 allocatedThreads = m_ThreadPool.ActiveThreads;
1764 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1765 }
1762 } 1766 }
1763 else if ( 1767 else if (
1764 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 1768 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
@@ -1863,6 +1867,12 @@ namespace OpenSim.Framework
1863 /// </summary> 1867 /// </summary>
1864 public static void PrintCallStack() 1868 public static void PrintCallStack()
1865 { 1869 {
1870 PrintCallStack(m_log.DebugFormat);
1871 }
1872
1873 public delegate void DebugPrinter(string msg, params Object[] parm);
1874 public static void PrintCallStack(DebugPrinter printer)
1875 {
1866 StackTrace stackTrace = new StackTrace(true); // get call stack 1876 StackTrace stackTrace = new StackTrace(true); // get call stack
1867 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) 1877 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1868 1878
@@ -1870,7 +1880,7 @@ namespace OpenSim.Framework
1870 foreach (StackFrame stackFrame in stackFrames) 1880 foreach (StackFrame stackFrame in stackFrames)
1871 { 1881 {
1872 MethodBase mb = stackFrame.GetMethod(); 1882 MethodBase mb = stackFrame.GetMethod();
1873 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name 1883 printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1874 } 1884 }
1875 } 1885 }
1876 1886
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index d604cf6..ed8ec16 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock;
44namespace OpenSim.Region.ClientStack.Linden.Tests 44namespace OpenSim.Region.ClientStack.Linden.Tests
45{ 45{
46 [TestFixture] 46 [TestFixture]
47 public class EventQueueTests 47 public class EventQueueTests : OpenSimTestCase
48 { 48 {
49 private TestScene m_scene; 49 private TestScene m_scene;
50 50
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 4860da0..ee66485 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -12122,11 +12122,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12122 if (logPacket) 12122 if (logPacket)
12123 m_log.DebugFormat( 12123 m_log.DebugFormat(
12124 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", 12124 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
12125 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); 12125 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
12126 } 12126 }
12127 12127
12128 if (!ProcessPacketMethod(packet)) 12128 if (!ProcessPacketMethod(packet))
12129 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 12129 m_log.WarnFormat(
12130 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
12131 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
12130 } 12132 }
12131 12133
12132 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 12134 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
index 5fcf376..7d9f581 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs
@@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock;
43namespace OpenSim.Region.ClientStack.LindenUDP.Tests 43namespace OpenSim.Region.ClientStack.LindenUDP.Tests
44{ 44{
45 [TestFixture] 45 [TestFixture]
46 public class LLImageManagerTests 46 public class LLImageManagerTests : OpenSimTestCase
47 { 47 {
48 private AssetBase m_testImageAsset; 48 private AssetBase m_testImageAsset;
49 private Scene scene; 49 private Scene scene;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
index 0f88ec6..5f73a94 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
39 /// Tests for the LL packet handler 39 /// Tests for the LL packet handler
40 /// </summary> 40 /// </summary>
41 [TestFixture] 41 [TestFixture]
42 public class PacketHandlerTests 42 public class PacketHandlerTests : OpenSimTestCase
43 { 43 {
44// [Test] 44// [Test]
45// /// <summary> 45// /// <summary>
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
index 1c2bfd0..fd02b08 100644
--- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -47,14 +47,16 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
47 /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. 47 /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
48 /// </summary> 48 /// </summary>
49 [TestFixture] 49 [TestFixture]
50 public class FlotsamAssetCacheTests 50 public class FlotsamAssetCacheTests : OpenSimTestCase
51 { 51 {
52 protected TestScene m_scene; 52 protected TestScene m_scene;
53 protected FlotsamAssetCache m_cache; 53 protected FlotsamAssetCache m_cache;
54 54
55 [SetUp] 55 [SetUp]
56 public void SetUp() 56 public override void SetUp()
57 { 57 {
58 base.SetUp();
59
58 IConfigSource config = new IniConfigSource(); 60 IConfigSource config = new IniConfigSource();
59 61
60 config.AddConfig("Modules"); 62 config.AddConfig("Modules");
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index 848b3bf..1830d41 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -39,7 +39,7 @@ using OpenSim.Tests.Common.Mock;
39namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 39namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
40{ 40{
41 [TestFixture] 41 [TestFixture]
42 public class AvatarFactoryModuleTests 42 public class AvatarFactoryModuleTests : OpenSimTestCase
43 { 43 {
44 /// <summary> 44 /// <summary>
45 /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. 45 /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service.
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
index 7a197f7..961117e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
40namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests 40namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class FriendsModuleTests 43 public class FriendsModuleTests : OpenSimTestCase
44 { 44 {
45 private FriendsModule m_fm; 45 private FriendsModule m_fm;
46 private TestScene m_scene; 46 private TestScene m_scene;
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index af54c1a..b735c61 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
81 } 81 }
82 82
83 if (groupsConfig.GetString("Module", "Default") != "Default") 83 if (groupsConfig.GetString("Module", "Default") != "Default")
84 {
85 m_Enabled = false;
84 return; 86 return;
87 }
85 } 88 }
86 89
87 } 90 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index cc266df..1627f6c 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
153 if (sp != null && !sp.IsChildAgent) 153 if (sp != null && !sp.IsChildAgent)
154 { 154 {
155 // Local message 155 // Local message
156 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); 156// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
157 157
158 sp.ControllingClient.SendInstantMessage(im); 158 sp.ControllingClient.SendInstantMessage(im);
159 159
@@ -166,14 +166,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
166 // try child avatar second 166 // try child avatar second
167 foreach (Scene scene in m_Scenes) 167 foreach (Scene scene in m_Scenes)
168 { 168 {
169 //m_log.DebugFormat( 169// m_log.DebugFormat(
170 // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); 170// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
171 171
172 ScenePresence sp = scene.GetScenePresence(toAgentID); 172 ScenePresence sp = scene.GetScenePresence(toAgentID);
173 if (sp != null) 173 if (sp != null)
174 { 174 {
175 // Local message 175 // Local message
176 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); 176// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
177 177
178 sp.ControllingClient.SendInstantMessage(im); 178 sp.ControllingClient.SendInstantMessage(im);
179 179
@@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
183 } 183 }
184 } 184 }
185 185
186 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); 186// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
187 187
188 SendGridInstantMessageViaXMLRPC(im, result); 188 SendGridInstantMessageViaXMLRPC(im, result);
189 } 189 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index 3a44cc5..2d46276 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
189 { 189 {
190 foreach (GridInstantMessage im in msglist) 190 foreach (GridInstantMessage im in msglist)
191 { 191 {
192 // client.SendInstantMessage(im); 192 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
193 193 // send it directly or else the item will be given twice
194 // Send through scene event manager so all modules get a chance 194 client.SendInstantMessage(im);
195 // to look at this message before it gets delivered. 195 else
196 // 196 {
197 // Needed for proper state management for stored group 197 // Send through scene event manager so all modules get a chance
198 // invitations 198 // to look at this message before it gets delivered.
199 // 199 //
200 200 // Needed for proper state management for stored group
201 im.offline = 1; 201 // invitations
202 202 //
203 Scene s = FindScene(client.AgentId); 203
204 if (s != null) 204 im.offline = 1;
205 s.EventManager.TriggerIncomingInstantMessage(im); 205
206 Scene s = FindScene(client.AgentId);
207 if (s != null)
208 s.EventManager.TriggerIncomingInstantMessage(im);
209 }
206 } 210 }
207 } 211 }
208 } 212 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index 4cfa33d..ae58dfd 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -316,76 +316,74 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
316 } 316 }
317 } 317 }
318 318
319 // Disabled for now as it looks like http://opensimulator.org/mantis/view.php?id=6311 was fixed by fixes 319 // XXX: This code was placed here to try and accomodate RLV which moves given folders named #RLV/~<name>
320 // to inventory folder versioning allowing the viewer to move the received folder itself as happens on the 320 // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be
321 // LL grid. Doing it again server-side then wrongly does a second create and move 321 // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet
322// // XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name> 322 // happening, possibly because we are not sending the correct inventory update messages with the correct
323// // to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis 323 // transaction IDs
324// // of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously 324 else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
325// // done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here. 325 {
326// else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) 326 UUID destinationFolderID = UUID.Zero;
327// { 327
328// UUID destinationFolderID = UUID.Zero; 328 if (im.binaryBucket != null && im.binaryBucket.Length >= 16)
329// 329 {
330// if (im.binaryBucket != null && im.binaryBucket.Length >= 16) 330 destinationFolderID = new UUID(im.binaryBucket, 0);
331// { 331 }
332// destinationFolderID = new UUID(im.binaryBucket, 0); 332
333// } 333 if (destinationFolderID != UUID.Zero)
334// 334 {
335// if (destinationFolderID != UUID.Zero) 335 InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId);
336// { 336 if (destinationFolder == null)
337// InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); 337 {
338// if (destinationFolder == null) 338 m_log.WarnFormat(
339// { 339 "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist",
340// m_log.WarnFormat( 340 client.Name, scene.Name, destinationFolderID);
341// "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", 341
342// client.Name, scene.Name, destinationFolderID); 342 return;
343// 343 }
344// return; 344
345// } 345 IInventoryService invService = scene.InventoryService;
346// 346
347// IInventoryService invService = scene.InventoryService; 347 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
348// 348
349// UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip 349 InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
350// 350 item = invService.GetItem(item);
351// InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); 351 InventoryFolderBase folder = null;
352// item = invService.GetItem(item); 352 UUID? previousParentFolderID = null;
353// InventoryFolderBase folder = null; 353
354// UUID? previousParentFolderID = null; 354 if (item != null) // It's an item
355// 355 {
356// if (item != null) // It's an item 356 previousParentFolderID = item.Folder;
357// { 357 item.Folder = destinationFolderID;
358// previousParentFolderID = item.Folder; 358
359// item.Folder = destinationFolderID; 359 invService.DeleteItems(item.Owner, new List<UUID>() { item.ID });
360// 360 scene.AddInventoryItem(client, item);
361// invService.DeleteItems(item.Owner, new List<UUID>() { item.ID }); 361 }
362// scene.AddInventoryItem(client, item); 362 else
363// } 363 {
364// else 364 folder = new InventoryFolderBase(inventoryID, client.AgentId);
365// { 365 folder = invService.GetFolder(folder);
366// folder = new InventoryFolderBase(inventoryID, client.AgentId); 366
367// folder = invService.GetFolder(folder); 367 if (folder != null) // It's a folder
368// 368 {
369// if (folder != null) // It's a folder 369 previousParentFolderID = folder.ParentID;
370// { 370 folder.ParentID = destinationFolderID;
371// previousParentFolderID = folder.ParentID; 371 invService.MoveFolder(folder);
372// folder.ParentID = destinationFolderID; 372 }
373// invService.MoveFolder(folder); 373 }
374// } 374
375// } 375 // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
376// 376 if (previousParentFolderID != null)
377// // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). 377 {
378// if (previousParentFolderID != null) 378 InventoryFolderBase previousParentFolder
379// { 379 = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
380// InventoryFolderBase previousParentFolder 380 previousParentFolder = invService.GetFolder(previousParentFolder);
381// = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); 381 scene.SendInventoryUpdate(client, previousParentFolder, true, true);
382// previousParentFolder = invService.GetFolder(previousParentFolder); 382
383// scene.SendInventoryUpdate(client, previousParentFolder, true, true); 383 scene.SendInventoryUpdate(client, destinationFolder, true, true);
384// 384 }
385// scene.SendInventoryUpdate(client, destinationFolder, true, true); 385 }
386// } 386 }
387// }
388// }
389 else if ( 387 else if (
390 im.dialog == (byte)InstantMessageDialog.InventoryDeclined 388 im.dialog == (byte)InstantMessageDialog.InventoryDeclined
391 || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined) 389 || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined)
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index f8ec6de..7871eda 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
71 71
72 #region Internal functions 72 #region Internal functions
73 73
74 public AssetMetadata FetchMetadata(string url, UUID assetID) 74 private 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 + "/";
@@ -86,6 +86,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
86 return meta; 86 return meta;
87 } 87 }
88 88
89 private AssetBase FetchAsset(string url, UUID assetID)
90 {
91 // Test if it's already here
92 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
93 if (asset == null)
94 {
95 if (!url.EndsWith("/") && !url.EndsWith("="))
96 url = url + "/";
97
98 asset = m_scene.AssetService.Get(url + assetID.ToString());
99
100 //if (asset != null)
101 // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url);
102 //else
103 // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url);
104
105 }
106
107 return asset;
108 }
109
89 public bool PostAsset(string url, AssetBase asset) 110 public bool PostAsset(string url, AssetBase asset)
90 { 111 {
91 if (asset != null) 112 if (asset != null)
@@ -228,11 +249,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
228 if (meta == null) 249 if (meta == null)
229 return; 250 return;
230 251
231 // The act of gathering UUIDs downloads the assets from the remote server 252 // The act of gathering UUIDs downloads some assets from the remote server
253 // but not all...
232 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 254 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
233 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); 255 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
234 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); 256 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
235 257 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count);
258 bool success = true;
259 foreach (UUID uuid in ids.Keys)
260 if (FetchAsset(userAssetURL, uuid) == null)
261 success = false;
262
263 // maybe all pieces got here...
264 if (!success)
265 m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL);
266 else
267 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
236 } 268 }
237 269
238 270
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index 21d8bd7..ac25a93 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
@@ -49,7 +49,7 @@ using OpenSim.Tests.Common.Mock;
49namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests 49namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
50{ 50{
51 [TestFixture] 51 [TestFixture]
52 public class InventoryAccessModuleTests 52 public class InventoryAccessModuleTests : OpenSimTestCase
53 { 53 {
54 protected TestScene m_scene; 54 protected TestScene m_scene;
55 protected BasicInventoryAccessModule m_iam; 55 protected BasicInventoryAccessModule m_iam;
@@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
57 protected TestClient m_tc; 57 protected TestClient m_tc;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 m_iam = new BasicInventoryAccessModule(); 64 m_iam = new BasicInventoryAccessModule();
63 65
64 IConfigSource config = new IniConfigSource(); 66 IConfigSource config = new IniConfigSource();
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index 86e7004..77e8b00 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -181,6 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
181 181
182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); 182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
183 183
184 // searhc the user accounts service
184 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); 185 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
185 186
186 List<UserData> users = new List<UserData>(); 187 List<UserData> users = new List<UserData>();
@@ -196,6 +197,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
196 } 197 }
197 } 198 }
198 199
200 // search the local cache
201 foreach (UserData data in m_UserCache.Values)
202 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
203 (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
204 users.Add(data);
205
199 AddAdditionalUsers(avatarID, query, users); 206 AddAdditionalUsers(avatarID, query, users);
200 207
201 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 208 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
@@ -433,6 +440,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
433 public void AddUser(UUID uuid, string first, string last, string homeURL) 440 public void AddUser(UUID uuid, string first, string last, string homeURL)
434 { 441 {
435 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); 442 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
443 if (homeURL == string.Empty)
444 return;
445
436 AddUser(uuid, homeURL + ";" + first + " " + last); 446 AddUser(uuid, homeURL + ";" + first + " " + last);
437 } 447 }
438 448
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
index 32e47f9..69bac82 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
@@ -35,7 +35,6 @@ using NUnit.Framework;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using Nini.Config; 37using Nini.Config;
38
39using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; 38using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; 40using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
@@ -44,11 +43,14 @@ using OpenSim.Tests.Common;
44namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests 43namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
45{ 44{
46 [TestFixture] 45 [TestFixture]
47 public class PresenceConnectorsTests 46 public class PresenceConnectorsTests : OpenSimTestCase
48 { 47 {
49 LocalPresenceServicesConnector m_LocalConnector; 48 LocalPresenceServicesConnector m_LocalConnector;
50 private void SetUp() 49
50 public override void SetUp()
51 { 51 {
52 base.SetUp();
53
52 IConfigSource config = new IniConfigSource(); 54 IConfigSource config = new IniConfigSource();
53 config.AddConfig("Modules"); 55 config.AddConfig("Modules");
54 config.AddConfig("PresenceService"); 56 config.AddConfig("PresenceService");
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index ade5e76..01f1c63 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -570,13 +570,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver
570 570
571 // Validate User and Group UUID's 571 // Validate User and Group UUID's
572 572
573 if (!ResolveUserUuid(scene, parcel.OwnerID)) 573 if (parcel.IsGroupOwned)
574 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
575
576 if (!ResolveGroupUuid(parcel.GroupID))
577 { 574 {
578 parcel.GroupID = UUID.Zero; 575 if (!ResolveGroupUuid(parcel.GroupID))
579 parcel.IsGroupOwned = false; 576 {
577 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
578 parcel.GroupID = UUID.Zero;
579 parcel.IsGroupOwned = false;
580 }
581 }
582 else
583 {
584 if (!ResolveUserUuid(scene, parcel.OwnerID))
585 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
586
587 if (!ResolveGroupUuid(parcel.GroupID))
588 parcel.GroupID = UUID.Zero;
580 } 589 }
581 590
582 List<LandAccessEntry> accessList = new List<LandAccessEntry>(); 591 List<LandAccessEntry> accessList = new List<LandAccessEntry>();
@@ -589,8 +598,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
589 parcel.ParcelAccessList = accessList; 598 parcel.ParcelAccessList = accessList;
590 599
591// m_log.DebugFormat( 600// m_log.DebugFormat(
592// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}", 601// "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}",
593// parcel.Name, parcel.LocalID, parcel.Area); 602// parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area);
594 603
595 landData.Add(parcel); 604 landData.Add(parcel);
596 } 605 }
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
index d751b1c..7bdd65c 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -167,7 +167,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
167 } 167 }
168 scenesGroup.CalcSceneLocations(); 168 scenesGroup.CalcSceneLocations();
169 169
170
171 m_archiveWriter = new TarArchiveWriter(m_saveStream); 170 m_archiveWriter = new TarArchiveWriter(m_saveStream);
172 171
173 try 172 try
@@ -216,7 +215,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
216 } 215 }
217 } 216 }
218 217
219
220 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) 218 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
221 { 219 {
222 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); 220 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
@@ -540,7 +538,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
540 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 538 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
541 } 539 }
542 540
543
544 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) 541 protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
545 { 542 {
546 if (regionDir != string.Empty) 543 if (regionDir != string.Empty)
@@ -560,8 +557,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
560 foreach (ILandObject lo in landObjects) 557 foreach (ILandObject lo in landObjects)
561 { 558 {
562 LandData landData = lo.LandData; 559 LandData landData = lo.LandData;
563 string landDataPath = String.Format("{0}{1}{2}.xml", 560 string landDataPath
564 regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); 561 = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData));
565 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); 562 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
566 } 563 }
567 564
@@ -604,7 +601,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
604 601
605 CloseArchive(String.Empty); 602 CloseArchive(String.Empty);
606 } 603 }
607
608 604
609 /// <summary> 605 /// <summary>
610 /// Closes the archive and notifies that we're done. 606 /// Closes the archive and notifies that we're done.
@@ -629,6 +625,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
629 625
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); 626 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 } 627 }
632
633 } 628 }
634} 629} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index 82f49b0..eec1cec 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -31,16 +31,19 @@ using System.IO;
31using System.Reflection; 31using System.Reflection;
32using System.Threading; 32using System.Threading;
33using log4net.Config; 33using log4net.Config;
34using Nini.Config;
34using NUnit.Framework; 35using NUnit.Framework;
35using OpenMetaverse; 36using OpenMetaverse;
36using OpenMetaverse.Assets; 37using OpenMetaverse.Assets;
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Framework.Serialization; 39using OpenSim.Framework.Serialization;
39using OpenSim.Framework.Serialization.External; 40using OpenSim.Framework.Serialization.External;
41using OpenSim.Region.CoreModules.World.Land;
40using OpenSim.Region.CoreModules.World.Serialiser; 42using OpenSim.Region.CoreModules.World.Serialiser;
41using OpenSim.Region.CoreModules.World.Terrain; 43using OpenSim.Region.CoreModules.World.Terrain;
42using OpenSim.Region.Framework.Scenes; 44using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 45using OpenSim.Region.Framework.Scenes.Serialization;
46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
44using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
45using OpenSim.Tests.Common.Mock; 48using OpenSim.Tests.Common.Mock;
46using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; 49using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
@@ -69,9 +72,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
69 { 72 {
70 base.SetUp(); 73 base.SetUp();
71 74
72 // FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later
73 new SceneManager();
74
75 m_archiverModule = new ArchiverModule(); 75 m_archiverModule = new ArchiverModule();
76 m_serialiserModule = new SerialiserModule(); 76 m_serialiserModule = new SerialiserModule();
77 TerrainModule terrainModule = new TerrainModule(); 77 TerrainModule terrainModule = new TerrainModule();
@@ -127,6 +127,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
127 127
128 return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; 128 return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName };
129 } 129 }
130
131 private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
132 {
133 SceneObjectPart part1 = CreateSceneObjectPart1();
134 sog1 = new SceneObjectGroup(part1);
135 scene.AddNewSceneObject(sog1, false);
136
137 AssetNotecard nc = new AssetNotecard();
138 nc.BodyText = "Hello World!";
139 nc.Encode();
140 ncAssetUuid = UUID.Random();
141 UUID ncItemUuid = UUID.Random();
142 AssetBase ncAsset
143 = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
144 m_scene.AssetService.Store(ncAsset);
145
146 TaskInventoryItem ncItem
147 = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
148 SceneObjectPart part2 = CreateSceneObjectPart2();
149 sog2 = new SceneObjectGroup(part2);
150 part2.Inventory.AddInventoryItem(ncItem, true);
151
152 scene.AddNewSceneObject(sog2, false);
153 }
154
155 private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
156 {
157 using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
158 {
159 using (BinaryReader br = new BinaryReader(resource))
160 {
161 // FIXME: Use the inspector instead
162 soundData = br.ReadBytes(99999999);
163 soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
164 string soundAssetFileName
165 = ArchiveConstants.ASSETS_PATH + soundUuid
166 + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
167 tar.WriteFile(soundAssetFileName, soundData);
168
169 /*
170 AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
171 scene.AssetService.Store(soundAsset);
172 asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
173 */
174 }
175 }
176 }
130 177
131 /// <summary> 178 /// <summary>
132 /// Test saving an OpenSim Region Archive. 179 /// Test saving an OpenSim Region Archive.
@@ -204,30 +251,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
204 // TODO: Test presence of more files and contents of files. 251 // TODO: Test presence of more files and contents of files.
205 } 252 }
206 253
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
231 /// <summary> 254 /// <summary>
232 /// Test saving an OpenSim Region Archive with the no assets option 255 /// Test saving an OpenSim Region Archive with the no assets option
233 /// </summary> 256 /// </summary>
@@ -309,59 +332,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
309 } 332 }
310 333
311 /// <summary> 334 /// <summary>
312 /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
313 /// 2 can come after 3).
314 /// </summary>
315 [Test]
316 public void TestLoadOarUnorderedParts()
317 {
318 TestHelpers.InMethod();
319
320 UUID ownerId = TestHelpers.ParseTail(0xaaaa);
321
322 MemoryStream archiveWriteStream = new MemoryStream();
323 TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
324
325 tar.WriteFile(
326 ArchiveConstants.CONTROL_FILE_PATH,
327 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
328
329 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
330 SceneObjectPart sop2
331 = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
332 SceneObjectPart sop3
333 = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
334
335 // Add the parts so they will be written out in reverse order to the oar
336 sog1.AddPart(sop3);
337 sop3.LinkNum = 3;
338 sog1.AddPart(sop2);
339 sop2.LinkNum = 2;
340
341 tar.WriteFile(
342 ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
343 SceneObjectSerializer.ToXml2Format(sog1));
344
345 tar.Close();
346
347 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
348
349 lock (this)
350 {
351 m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
352 m_archiverModule.DearchiveRegion(archiveReadStream);
353 }
354
355 Assert.That(m_lastErrorMessage, Is.Null);
356
357 SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
358 Assert.That(part2.LinkNum, Is.EqualTo(2));
359
360 SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
361 Assert.That(part3.LinkNum, Is.EqualTo(3));
362 }
363
364 /// <summary>
365 /// Test loading an OpenSim Region Archive. 335 /// Test loading an OpenSim Region Archive.
366 /// </summary> 336 /// </summary>
367 [Test] 337 [Test]
@@ -435,50 +405,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
435 TestLoadedRegion(part1, soundItemName, soundData); 405 TestLoadedRegion(part1, soundItemName, soundData);
436 } 406 }
437 407
438 private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) 408 /// <summary>
409 /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
410 /// 2 can come after 3).
411 /// </summary>
412 [Test]
413 public void TestLoadOarUnorderedParts()
439 { 414 {
440 using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) 415 TestHelpers.InMethod();
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 416
452 /* 417 UUID ownerId = TestHelpers.ParseTail(0xaaaa);
453 AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
454 scene.AssetService.Store(soundAsset);
455 asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
456 */
457 }
458 }
459 }
460 418
461 private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) 419 MemoryStream archiveWriteStream = new MemoryStream();
462 { 420 TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
463 SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
464 421
465 Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); 422 tar.WriteFile(
466 Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); 423 ArchiveConstants.CONTROL_FILE_PATH,
467 Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); 424 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
468 Assert.That(
469 object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
470 Assert.That(
471 object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
472 Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
473 Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
474 425
475 TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; 426 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
476 Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); 427 SceneObjectPart sop2
477 AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); 428 = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
478 Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); 429 SceneObjectPart sop3
479 Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); 430 = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
480 431
481 Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); 432 // Add the parts so they will be written out in reverse order to the oar
433 sog1.AddPart(sop3);
434 sop3.LinkNum = 3;
435 sog1.AddPart(sop2);
436 sop2.LinkNum = 2;
437
438 tar.WriteFile(
439 ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
440 SceneObjectSerializer.ToXml2Format(sog1));
441
442 tar.Close();
443
444 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
445
446 lock (this)
447 {
448 m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
449 m_archiverModule.DearchiveRegion(archiveReadStream);
450 }
451
452 Assert.That(m_lastErrorMessage, Is.Null);
453
454 SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
455 Assert.That(part2.LinkNum, Is.EqualTo(2));
456
457 SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
458 Assert.That(part3.LinkNum, Is.EqualTo(3));
482 } 459 }
483 460
484 /// <summary> 461 /// <summary>
@@ -538,8 +515,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
538 SerialiserModule serialiserModule = new SerialiserModule(); 515 SerialiserModule serialiserModule = new SerialiserModule();
539 TerrainModule terrainModule = new TerrainModule(); 516 TerrainModule terrainModule = new TerrainModule();
540 517
541 m_sceneHelpers = new SceneHelpers(); 518 SceneHelpers m_sceneHelpers2 = new SceneHelpers();
542 TestScene scene2 = m_sceneHelpers.SetupScene(); 519 TestScene scene2 = m_sceneHelpers2.SetupScene();
543 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); 520 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
544 521
545 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is 522 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
@@ -563,6 +540,71 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
563 } 540 }
564 541
565 /// <summary> 542 /// <summary>
543 /// Test OAR loading where the land parcel is group deeded.
544 /// </summary>
545 /// <remarks>
546 /// In this situation, the owner ID is set to the group ID.
547 /// </remarks>
548 [Test]
549 public void TestLoadOarDeededLand()
550 {
551 TestHelpers.InMethod();
552// TestHelpers.EnableLogging();
553
554 UUID landID = TestHelpers.ParseTail(0x10);
555
556 MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector();
557
558 IConfigSource configSource = new IniConfigSource();
559 IConfig config = configSource.AddConfig("Groups");
560 config.Set("Enabled", true);
561 config.Set("Module", "GroupsModule");
562 config.Set("DebugEnabled", true);
563 SceneHelpers.SetupSceneModules(
564 m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() });
565
566 // Create group in scene for loading
567 // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests.
568 UUID groupID
569 = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero);
570
571 // Construct OAR
572 MemoryStream oarStream = new MemoryStream();
573 TarArchiveWriter tar = new TarArchiveWriter(oarStream);
574
575 tar.WriteDir(ArchiveConstants.LANDDATA_PATH);
576 tar.WriteFile(
577 ArchiveConstants.CONTROL_FILE_PATH,
578 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
579
580 LandObject lo = new LandObject(groupID, true, null);
581 lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
582 LandData ld = lo.LandData;
583 ld.GlobalID = landID;
584
585 string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
586 tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null));
587 tar.Close();
588
589 oarStream = new MemoryStream(oarStream.ToArray());
590
591 // Load OAR
592 lock (this)
593 {
594 m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
595 m_archiverModule.DearchiveRegion(oarStream);
596 }
597
598 ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16);
599 LandData rLd = rLo.LandData;
600
601 Assert.That(rLd.GlobalID, Is.EqualTo(landID));
602 Assert.That(rLd.OwnerID, Is.EqualTo(groupID));
603 Assert.That(rLd.GroupID, Is.EqualTo(groupID));
604 Assert.That(rLd.IsGroupOwned, Is.EqualTo(true));
605 }
606
607 /// <summary>
566 /// Test loading the region settings of an OpenSim Region Archive. 608 /// Test loading the region settings of an OpenSim Region Archive.
567 /// </summary> 609 /// </summary>
568 [Test] 610 [Test]
@@ -781,9 +823,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
781 } 823 }
782 } 824 }
783 825
784
785 // Save OAR 826 // Save OAR
786
787 MemoryStream archiveWriteStream = new MemoryStream(); 827 MemoryStream archiveWriteStream = new MemoryStream();
788 m_scene.EventManager.OnOarFileSaved += SaveCompleted; 828 m_scene.EventManager.OnOarFileSaved += SaveCompleted;
789 829
@@ -800,7 +840,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
800 840
801 841
802 // Check that the OAR contains the expected data 842 // Check that the OAR contains the expected data
803
804 Assert.That(m_lastRequestId, Is.EqualTo(requestId)); 843 Assert.That(m_lastRequestId, Is.EqualTo(requestId));
805 844
806 byte[] archive = archiveWriteStream.ToArray(); 845 byte[] archive = archiveWriteStream.ToArray();
@@ -892,7 +931,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
892 } 931 }
893 932
894 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); 933 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
895 SceneManager.Instance.ForEachScene(delegate(Scene scene) 934 m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
896 { 935 {
897 scenesGroup.AddScene(scene); 936 scenesGroup.AddScene(scene);
898 }); 937 });
@@ -950,13 +989,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
950 989
951 // Delete the current objects, to test that they're loaded from the OAR and didn't 990 // Delete the current objects, to test that they're loaded from the OAR and didn't
952 // just remain in the scene. 991 // just remain in the scene.
953 SceneManager.Instance.ForEachScene(delegate(Scene scene) 992 m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
954 { 993 {
955 scene.DeleteAllSceneObjects(); 994 scene.DeleteAllSceneObjects();
956 }); 995 });
957 996
958 // Create a "hole", to test that that the corresponding region isn't loaded from the OAR 997 // Create a "hole", to test that that the corresponding region isn't loaded from the OAR
959 SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]); 998 m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]);
960 999
961 1000
962 // Check thay the OAR file contains the expected data 1001 // Check thay the OAR file contains the expected data
@@ -971,10 +1010,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
971 1010
972 Assert.That(m_lastErrorMessage, Is.Null); 1011 Assert.That(m_lastErrorMessage, Is.Null);
973 1012
974 Assert.AreEqual(3, SceneManager.Instance.Scenes.Count); 1013 Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count);
975 1014
976 TestLoadedRegion(part1, soundItemName, soundData); 1015 TestLoadedRegion(part1, soundItemName, soundData);
977 } 1016 }
978 1017
1018 private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
1019 {
1020 SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
1021
1022 Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
1023 Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
1024 Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
1025 Assert.That(
1026 object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
1027 Assert.That(
1028 object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
1029 Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
1030 Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
1031
1032 TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
1033 Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
1034 AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
1035 Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
1036 Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
1037
1038 Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
1039 }
979 } 1040 }
980} 1041} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index dc062b6..267332d 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -55,6 +55,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
55 55
56 protected EstateManagementCommands m_commands; 56 protected EstateManagementCommands m_commands;
57 57
58 /// <summary>
59 /// If false, region restart requests from the client are blocked even if they are otherwise legitimate.
60 /// </summary>
61 public bool AllowRegionRestartFromClient { get; set; }
62
58 private EstateTerrainXferHandler TerrainUploader; 63 private EstateTerrainXferHandler TerrainUploader;
59 public TelehubManager m_Telehub; 64 public TelehubManager m_Telehub;
60 65
@@ -64,6 +69,53 @@ namespace OpenSim.Region.CoreModules.World.Estate
64 69
65 private int m_delayCount = 0; 70 private int m_delayCount = 0;
66 71
72 #region Region Module interface
73
74 public string Name { get { return "EstateManagementModule"; } }
75
76 public Type ReplaceableInterface { get { return null; } }
77
78 public void Initialise(IConfigSource source)
79 {
80 AllowRegionRestartFromClient = true;
81
82 IConfig config = source.Configs["EstateManagement"];
83
84 if (config != null)
85 AllowRegionRestartFromClient = config.GetBoolean("AllowRegionRestartFromClient", true);
86 }
87
88 public void AddRegion(Scene scene)
89 {
90 Scene = scene;
91 Scene.RegisterModuleInterface<IEstateModule>(this);
92 Scene.EventManager.OnNewClient += EventManager_OnNewClient;
93 Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
94
95 m_Telehub = new TelehubManager(scene);
96
97 m_commands = new EstateManagementCommands(this);
98 m_commands.Initialise();
99 }
100
101 public void RemoveRegion(Scene scene) {}
102
103 public void RegionLoaded(Scene scene)
104 {
105 // Sets up the sun module based no the saved Estate and Region Settings
106 // DO NOT REMOVE or the sun will stop working
107 scene.TriggerEstateSunUpdate();
108
109 UserManager = scene.RequestModuleInterface<IUserManagement>();
110 }
111
112 public void Close()
113 {
114 m_commands.Close();
115 }
116
117 #endregion
118
67 #region Packet Data Responders 119 #region Packet Data Responders
68 120
69 private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) 121 private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice)
@@ -197,6 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
197 Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; 249 Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture;
198 break; 250 break;
199 } 251 }
252
200 Scene.RegionInfo.RegionSettings.Save(); 253 Scene.RegionInfo.RegionSettings.Save();
201 TriggerRegionInfoChange(); 254 TriggerRegionInfoChange();
202 sendRegionInfoPacketToAll(); 255 sendRegionInfoPacketToAll();
@@ -228,6 +281,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
228 Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; 281 Scene.RegionInfo.RegionSettings.Elevation2NE = highValue;
229 break; 282 break;
230 } 283 }
284
231 Scene.RegionInfo.RegionSettings.Save(); 285 Scene.RegionInfo.RegionSettings.Save();
232 TriggerRegionInfoChange(); 286 TriggerRegionInfoChange();
233 sendRegionHandshakeToAll(); 287 sendRegionHandshakeToAll();
@@ -268,6 +322,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
268 322
269 private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) 323 private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds)
270 { 324 {
325 if (!AllowRegionRestartFromClient)
326 {
327 remoteClient.SendAlertMessage("Region restart has been disabled on this simulator.");
328 return;
329 }
330
271 IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); 331 IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>();
272 if (restartModule != null) 332 if (restartModule != null)
273 { 333 {
@@ -352,6 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
352 } 412 }
353 413
354 } 414 }
415
355 if ((estateAccessType & 8) != 0) // User remove 416 if ((estateAccessType & 8) != 0) // User remove
356 { 417 {
357 if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) 418 if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
@@ -383,6 +444,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
383 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); 444 remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
384 } 445 }
385 } 446 }
447
386 if ((estateAccessType & 16) != 0) // Group add 448 if ((estateAccessType & 16) != 0) // Group add
387 { 449 {
388 if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) 450 if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
@@ -650,7 +712,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
650 } 712 }
651 } 713 }
652 714
653 public void handleOnEstateManageTelehub (IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) 715 public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
654 { 716 {
655 SceneObjectPart part; 717 SceneObjectPart part;
656 718
@@ -1118,49 +1180,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
1118 1180
1119 #endregion 1181 #endregion
1120 1182
1121 #region Region Module interface
1122
1123 public string Name { get { return "EstateManagementModule"; } }
1124
1125 public Type ReplaceableInterface { get { return null; } }
1126
1127 public void Initialise(IConfigSource source) {}
1128
1129 public void AddRegion(Scene scene)
1130 {
1131 m_regionChangeTimer.AutoReset = false;
1132 m_regionChangeTimer.Interval = 2000;
1133 m_regionChangeTimer.Elapsed += RaiseRegionInfoChange;
1134
1135 Scene = scene;
1136 Scene.RegisterModuleInterface<IEstateModule>(this);
1137 Scene.EventManager.OnNewClient += EventManager_OnNewClient;
1138 Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
1139
1140 m_Telehub = new TelehubManager(scene);
1141
1142 m_commands = new EstateManagementCommands(this);
1143 m_commands.Initialise();
1144 }
1145
1146 public void RemoveRegion(Scene scene) {}
1147
1148 public void RegionLoaded(Scene scene)
1149 {
1150 // Sets up the sun module based no the saved Estate and Region Settings
1151 // DO NOT REMOVE or the sun will stop working
1152 scene.TriggerEstateSunUpdate();
1153
1154 UserManager = scene.RequestModuleInterface<IUserManagement>();
1155 }
1156
1157 public void Close()
1158 {
1159 m_commands.Close();
1160 }
1161
1162 #endregion
1163
1164 #region Other Functions 1183 #region Other Functions
1165 1184
1166 public void changeWaterHeight(float height) 1185 public void changeWaterHeight(float height)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 1193057..281c143 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -1384,9 +1384,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1384 } 1384 }
1385 1385
1386 for (int i = 0; i < data.Count; i++) 1386 for (int i = 0; i < data.Count; i++)
1387 {
1388 IncomingLandObjectFromStorage(data[i]); 1387 IncomingLandObjectFromStorage(data[i]);
1389 }
1390 } 1388 }
1391 1389
1392 public void IncomingLandObjectFromStorage(LandData data) 1390 public void IncomingLandObjectFromStorage(LandData data)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index d5b2adb..8ddff99 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -748,9 +748,10 @@ namespace OpenSim.Region.CoreModules.World.Land
748 int ty = min_y * 4; 748 int ty = min_y * 4;
749 if (ty > ((int)Constants.RegionSize - 1)) 749 if (ty > ((int)Constants.RegionSize - 1))
750 ty = ((int)Constants.RegionSize - 1); 750 ty = ((int)Constants.RegionSize - 1);
751
751 LandData.AABBMin = 752 LandData.AABBMin =
752 new Vector3((float) (min_x * 4), (float) (min_y * 4), 753 new Vector3(
753 (float) m_scene.Heightmap[tx, ty]); 754 (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
754 755
755 tx = max_x * 4; 756 tx = max_x * 4;
756 if (tx > ((int)Constants.RegionSize - 1)) 757 if (tx > ((int)Constants.RegionSize - 1))
@@ -758,9 +759,11 @@ namespace OpenSim.Region.CoreModules.World.Land
758 ty = max_y * 4; 759 ty = max_y * 4;
759 if (ty > ((int)Constants.RegionSize - 1)) 760 if (ty > ((int)Constants.RegionSize - 1))
760 ty = ((int)Constants.RegionSize - 1); 761 ty = ((int)Constants.RegionSize - 1);
761 LandData.AABBMax = 762
762 new Vector3((float) (max_x * 4), (float) (max_y * 4), 763 LandData.AABBMax
763 (float) m_scene.Heightmap[tx, ty]); 764 = new Vector3(
765 (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
766
764 LandData.Area = tempArea; 767 LandData.Area = tempArea;
765 } 768 }
766 769
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
index b5ee4d2..0945b43 100644
--- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock;
41namespace OpenSim.Region.CoreModules.World.Land.Tests 41namespace OpenSim.Region.CoreModules.World.Land.Tests
42{ 42{
43 [TestFixture] 43 [TestFixture]
44 public class PrimCountModuleTests 44 public class PrimCountModuleTests : OpenSimTestCase
45 { 45 {
46 protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); 46 protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000");
47 protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); 47 protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000");
@@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests
60 protected ILandObject m_lo2; 60 protected ILandObject m_lo2;
61 61
62 [SetUp] 62 [SetUp]
63 public void SetUp() 63 public override void SetUp()
64 { 64 {
65 base.SetUp();
66
65 m_pcm = new PrimCountModule(); 67 m_pcm = new PrimCountModule();
66 LandManagementModule lmm = new LandManagementModule(); 68 LandManagementModule lmm = new LandManagementModule();
67 m_scene = new SceneHelpers().SetupScene(); 69 m_scene = new SceneHelpers().SetupScene();
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
index 396095a..03a96a4 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
@@ -44,14 +44,16 @@ using OpenSim.Tests.Common.Mock;
44namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests 44namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
45{ 45{
46 [TestFixture] 46 [TestFixture]
47 public class MoapTests 47 public class MoapTests : OpenSimTestCase
48 { 48 {
49 protected TestScene m_scene; 49 protected TestScene m_scene;
50 protected MoapModule m_module; 50 protected MoapModule m_module;
51 51
52 [SetUp] 52 [SetUp]
53 public void SetUp() 53 public override void SetUp()
54 { 54 {
55 base.SetUp();
56
55 m_module = new MoapModule(); 57 m_module = new MoapModule();
56 m_scene = new SceneHelpers().SetupScene(); 58 m_scene = new SceneHelpers().SetupScene();
57 SceneHelpers.SetupSceneModules(m_scene, m_module); 59 SceneHelpers.SetupSceneModules(m_scene, m_module);
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index ab8f143..7b235ae 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
365 365
366 if (mainParams.Count < 4) 366 if (mainParams.Count < 4)
367 { 367 {
368 m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); 368 //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
369 m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
369 return; 370 return;
370 } 371 }
371 372
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
405 406
406 if (mainParams.Count < 5) 407 if (mainParams.Count < 5)
407 { 408 {
409 //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
408 m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); 410 m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
409 return; 411 return;
410 } 412 }
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
445 447
446 if (mainParams.Count < 4) 448 if (mainParams.Count < 4)
447 { 449 {
448 m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); 450 m_console.OutputFormat("Usage: show part name [--regex] <name>");
451 //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
449 return; 452 return;
450 } 453 }
451 454
@@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
577 cdl.AddRow("Link number", sop.LinkNum); 580 cdl.AddRow("Link number", sop.LinkNum);
578 cdl.AddRow("Flags", sop.Flags); 581 cdl.AddRow("Flags", sop.Flags);
579 582
583 if (showFull)
584 {
585 PrimitiveBaseShape s = sop.Shape;
586 cdl.AddRow("FlexiDrag", s.FlexiDrag);
587 cdl.AddRow("FlexiEntry", s.FlexiEntry);
588 cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
589 cdl.AddRow("FlexiGravity", s.FlexiGravity);
590 cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
591 cdl.AddRow("HollowShape", s.HollowShape);
592 cdl.AddRow(
593 "LightColor",
594 string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
595 cdl.AddRow("FlexiDrag", s.LightCutoff);
596 cdl.AddRow("FlexiDrag", s.LightEntry);
597 cdl.AddRow("FlexiDrag", s.LightFalloff);
598 cdl.AddRow("FlexiDrag", s.LightIntensity);
599 cdl.AddRow("FlexiDrag", s.LightRadius);
600 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
601 cdl.AddRow("PathBegin", s.PathBegin);
602 cdl.AddRow("PathEnd", s.PathEnd);
603 cdl.AddRow("PathCurve", s.PathCurve);
604 cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
605 cdl.AddRow("PathRevolutions", s.PathRevolutions);
606 cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
607 cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
608 cdl.AddRow("FlexiDrag", s.PathSkew);
609 cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
610 cdl.AddRow("PathTwist", s.PathTwist);
611 cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
612 cdl.AddRow("PCode", s.PCode);
613 cdl.AddRow("ProfileBegin", s.ProfileBegin);
614 cdl.AddRow("ProfileEnd", s.ProfileEnd);
615 cdl.AddRow("ProfileHollow", s.ProfileHollow);
616 cdl.AddRow("ProfileShape", s.ProfileShape);
617 cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
618 cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
619 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
620 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
621 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
622 cdl.AddRow("Scale", s.Scale);
623 cdl.AddRow(
624 "SculptData",
625 string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
626 cdl.AddRow("SculptEntry", s.SculptEntry);
627 cdl.AddRow("SculptTexture", s.SculptTexture);
628 cdl.AddRow("SculptType", s.SculptType);
629 cdl.AddRow("State", s.State);
630
631 // TODO, unpack and display texture entries
632 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
633 }
634
580 object itemsOutput; 635 object itemsOutput;
581 if (showFull) 636 if (showFull)
582 { 637 {
@@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
588 itemsOutput = sop.Inventory.Count; 643 itemsOutput = sop.Inventory.Count;
589 } 644 }
590 645
591
592 cdl.AddRow("Items", itemsOutput); 646 cdl.AddRow("Items", itemsOutput);
593 647
594 return sb.Append(cdl.ToString()); 648 return sb.Append(cdl.ToString());
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
index 7825e3e..bcb8e2f 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
@@ -39,7 +39,7 @@ using OpenSim.Tests.Common;
39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
40{ 40{
41 [TestFixture] 41 [TestFixture]
42 public class SerialiserTests 42 public class SerialiserTests : OpenSimTestCase
43 { 43 {
44 private string xml = @" 44 private string xml = @"
45 <SceneObjectGroup> 45 <SceneObjectGroup>
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 513a8f5..883045a 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -43,8 +43,8 @@ namespace OpenSim.Region.CoreModules.World.Sound
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")] 43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")]
44 public class SoundModule : INonSharedRegionModule, ISoundModule 44 public class SoundModule : INonSharedRegionModule, ISoundModule
45 { 45 {
46 private static readonly ILog m_log = LogManager.GetLogger( 46// private static readonly ILog m_log = LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType); 47// MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private Scene m_scene; 49 private Scene m_scene;
50 50
@@ -76,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
76 76
77 public void RemoveRegion(Scene scene) 77 public void RemoveRegion(Scene scene)
78 { 78 {
79 m_scene.EventManager.OnClientLogin -= OnNewClient; 79 m_scene.EventManager.OnNewClient -= OnNewClient;
80 } 80 }
81 81
82 public void RegionLoaded(Scene scene) 82 public void RegionLoaded(Scene scene)
@@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.World.Sound
85 return; 85 return;
86 86
87 m_scene = scene; 87 m_scene = scene;
88 m_scene.EventManager.OnClientLogin += OnNewClient; 88 m_scene.EventManager.OnNewClient += OnNewClient;
89 89
90 m_scene.RegisterModuleInterface<ISoundModule>(this); 90 m_scene.RegisterModuleInterface<ISoundModule>(this);
91 } 91 }
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
index 3d4f762..be719ea 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
@@ -30,11 +30,12 @@ using NUnit.Framework;
30using OpenSim.Framework; 30using OpenSim.Framework;
31using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; 31using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
32using OpenSim.Region.Framework.Scenes; 32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
33 34
34namespace OpenSim.Region.CoreModules.World.Terrain.Tests 35namespace OpenSim.Region.CoreModules.World.Terrain.Tests
35{ 36{
36 [TestFixture] 37 [TestFixture]
37 public class TerrainTest 38 public class TerrainTest : OpenSimTestCase
38 { 39 {
39 [Test] 40 [Test]
40 public void BrushTest() 41 public void BrushTest()
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
index fd8e2b4..9de588c 100644
--- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
+++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules
66 public void Initialise(IConfigSource config) 66 public void Initialise(IConfigSource config)
67 { 67 {
68 m_windConfig = config.Configs["Wind"]; 68 m_windConfig = config.Configs["Wind"];
69 string desiredWindPlugin = m_dWindPluginName; 69// string desiredWindPlugin = m_dWindPluginName;
70 70
71 if (m_windConfig != null) 71 if (m_windConfig != null)
72 { 72 {
diff --git a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
index 6db6674..093d3f0 100644
--- a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
+++ b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
@@ -34,5 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces
34 void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); 34 void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url);
35 void ScriptRemoved(UUID itemID); 35 void ScriptRemoved(UUID itemID);
36 void ObjectRemoved(UUID objectID); 36 void ObjectRemoved(UUID objectID);
37 void UnRegisterReceiver(string channelID, UUID itemID);
37 } 38 }
38} 39}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 9458079..d18571c 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -26,9 +26,10 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Threading;
30using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net; 33using log4net;
33using OpenMetaverse; 34using OpenMetaverse;
34using OpenSim.Framework; 35using OpenSim.Framework;
@@ -113,6 +114,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation
113 if (m_scenePresence.IsChildAgent) 114 if (m_scenePresence.IsChildAgent)
114 return; 115 return;
115 116
117// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Removing animation {0} for {1}", animID, m_scenePresence.Name);
118
116 if (m_animations.Remove(animID)) 119 if (m_animations.Remove(animID))
117 SendAnimPack(); 120 SendAnimPack();
118 } 121 }
@@ -519,6 +522,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
519 if (m_scenePresence.IsChildAgent) 522 if (m_scenePresence.IsChildAgent)
520 return; 523 return;
521 524
525// m_log.DebugFormat(
526// "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'",
527// string.Join(",", Array.ConvertAll<UUID, string>(animations, a => a.ToString())),
528// string.Join(",", Array.ConvertAll<int, string>(seqs, s => s.ToString())),
529// string.Join(",", Array.ConvertAll<UUID, string>(objectIDs, o => o.ToString())));
530
522 m_scenePresence.Scene.ForEachClient( 531 m_scenePresence.Scene.ForEachClient(
523 delegate(IClientAPI client) 532 delegate(IClientAPI client)
524 { 533 {
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs
index b788a3c..7181313 100644
--- a/OpenSim/Region/Framework/Scenes/EntityManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using log4net; 32using log4net;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework;
34 35
35namespace OpenSim.Region.Framework.Scenes 36namespace OpenSim.Region.Framework.Scenes
36{ 37{
@@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes
38 { 39 {
39// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 40// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 41
41 private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>(); 42 private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities
43 = new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>();
42 44
43 public int Count 45 public int Count
44 { 46 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index c9d1205..65c50bf 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -683,12 +683,10 @@ namespace OpenSim.Region.Framework.Scenes
683 itemCopy.SalePrice = item.SalePrice; 683 itemCopy.SalePrice = item.SalePrice;
684 itemCopy.SaleType = item.SaleType; 684 itemCopy.SaleType = item.SaleType;
685 685
686 if (AddInventoryItem(itemCopy)) 686 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
687 { 687 if (invAccess != null)
688 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); 688 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
689 if (invAccess != null) 689 AddInventoryItem(itemCopy);
690 Util.FireAndForget(delegate { invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); });
691 }
692 690
693 if (!Permissions.BypassPermissions()) 691 if (!Permissions.BypassPermissions())
694 { 692 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index c99e37e..2a1949d 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -762,7 +762,12 @@ namespace OpenSim.Region.Framework.Scenes
762 // 762 //
763 // Out of memory 763 // Out of memory
764 // Operating system has killed the plugin 764 // Operating system has killed the plugin
765 m_sceneGraph.UnRecoverableError += RestartNow; 765 m_sceneGraph.UnRecoverableError
766 += () =>
767 {
768 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
769 RestartNow();
770 };
766 771
767 RegisterDefaultSceneEvents(); 772 RegisterDefaultSceneEvents();
768 773
@@ -6036,10 +6041,17 @@ Environment.Exit(1);
6036 GC.Collect(); 6041 GC.Collect();
6037 } 6042 }
6038 6043
6039 // Wrappers to get physics modules retrieve assets. Has to be done this way 6044 /// <summary>
6040 // because we can't assign the asset service to physics directly - at the 6045 /// Wrappers to get physics modules retrieve assets.
6041 // time physics are instantiated it's not registered but it will be by 6046 /// </summary>
6042 // the time the first prim exists. 6047 /// <remarks>
6048 /// Has to be done this way
6049 /// because we can't assign the asset service to physics directly - at the
6050 /// time physics are instantiated it's not registered but it will be by
6051 /// the time the first prim exists.
6052 /// </remarks>
6053 /// <param name="assetID"></param>
6054 /// <param name="callback"></param>
6043 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) 6055 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
6044 { 6056 {
6045 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); 6057 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 4ad8b11..2051a53 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -505,11 +505,19 @@ namespace OpenSim.Region.Framework.Scenes
505 505
506 if (Scene != null) 506 if (Scene != null)
507 { 507 {
508 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 508 if (
509 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 509 // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E)
510 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 510 // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
511 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W) 511 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N)
512 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S)) 512 // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
513 // Experimental change for better border crossings.
514 // The commented out original lines above would, it seems, trigger
515 // a border crossing a little early or late depending on which
516 // direction the object was moving.
517 (Scene.TestBorderCross(val, Cardinals.E)
518 || Scene.TestBorderCross(val, Cardinals.W)
519 || Scene.TestBorderCross(val, Cardinals.N)
520 || Scene.TestBorderCross(val, Cardinals.S))
513 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 521 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
514 { 522 {
515 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 523 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 2191cfa..c746690 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -2895,11 +2895,14 @@ namespace OpenSim.Region.Framework.Scenes
2895 2895
2896 public void PhysicsOutOfBounds(Vector3 pos) 2896 public void PhysicsOutOfBounds(Vector3 pos)
2897 { 2897 {
2898 m_log.Error("[PHYSICS]: Physical Object went out of bounds."); 2898 // Note: This is only being called on the root prim at this time.
2899
2900 m_log.ErrorFormat(
2901 "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.",
2902 Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition);
2899 2903
2900 RemFlag(PrimFlags.Physics); 2904 RemFlag(PrimFlags.Physics);
2901 DoPhysicsPropertyUpdate(false, true); 2905 DoPhysicsPropertyUpdate(false, true);
2902 //ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2903 } 2906 }
2904 2907
2905 public void PhysicsRequestingTerseUpdate() 2908 public void PhysicsRequestingTerseUpdate()
@@ -4549,7 +4552,7 @@ namespace OpenSim.Region.Framework.Scenes
4549 if (ParentGroup.RootPart == this) 4552 if (ParentGroup.RootPart == this)
4550 AngularVelocity = new Vector3(0, 0, 0); 4553 AngularVelocity = new Vector3(0, 0, 0);
4551 } 4554 }
4552 else 4555 else if (SetVD != wasVD)
4553 { 4556 {
4554 if (ParentGroup.Scene.CollidablePrims) 4557 if (ParentGroup.Scene.CollidablePrims)
4555 { 4558 {
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7ff163b..041eac2 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -216,8 +216,6 @@ namespace OpenSim.Region.Framework.Scenes
216 216
217 private Quaternion m_headrotation = Quaternion.Identity; 217 private Quaternion m_headrotation = Quaternion.Identity;
218 218
219 private string m_nextSitAnimation = String.Empty;
220
221 //PauPaw:Proper PID Controler for autopilot************ 219 //PauPaw:Proper PID Controler for autopilot************
222 public bool MovingToTarget { get; private set; } 220 public bool MovingToTarget { get; private set; }
223 public Vector3 MoveToPositionTarget { get; private set; } 221 public Vector3 MoveToPositionTarget { get; private set; }
@@ -2174,25 +2172,10 @@ namespace OpenSim.Region.Framework.Scenes
2174 StandUp(); 2172 StandUp();
2175 } 2173 }
2176 2174
2177// if (!String.IsNullOrEmpty(sitAnimation))
2178// {
2179// m_nextSitAnimation = sitAnimation;
2180// }
2181// else
2182// {
2183 m_nextSitAnimation = "SIT";
2184// }
2185
2186 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
2187 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 2175 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2188 2176
2189 if (part != null) 2177 if (part != null)
2190 { 2178 {
2191 if (!String.IsNullOrEmpty(part.SitAnimation))
2192 {
2193 m_nextSitAnimation = part.SitAnimation;
2194 }
2195
2196 m_requestedSitTargetID = part.LocalId; 2179 m_requestedSitTargetID = part.LocalId;
2197 m_requestedSitTargetUUID = targetID; 2180 m_requestedSitTargetUUID = targetID;
2198 2181
@@ -2264,18 +2247,6 @@ namespace OpenSim.Region.Framework.Scenes
2264 2247
2265 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) 2248 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2266 { 2249 {
2267 if (!String.IsNullOrEmpty(m_nextSitAnimation))
2268 {
2269 HandleAgentSit(remoteClient, agentID, m_nextSitAnimation);
2270 }
2271 else
2272 {
2273 HandleAgentSit(remoteClient, agentID, "SIT");
2274 }
2275 }
2276
2277 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation)
2278 {
2279 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 2250 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2280 2251
2281 if (part != null) 2252 if (part != null)
@@ -2347,7 +2318,12 @@ namespace OpenSim.Region.Framework.Scenes
2347 2318
2348 Velocity = Vector3.Zero; 2319 Velocity = Vector3.Zero;
2349 RemoveFromPhysicalScene(); 2320 RemoveFromPhysicalScene();
2350 2321
2322 String sitAnimation = "SIT";
2323 if (!String.IsNullOrEmpty(part.SitAnimation))
2324 {
2325 sitAnimation = part.SitAnimation;
2326 }
2351 Animator.TrySetMovementAnimation(sitAnimation); 2327 Animator.TrySetMovementAnimation(sitAnimation);
2352 SendAvatarDataToAllAgents(); 2328 SendAvatarDataToAllAgents();
2353 } 2329 }
diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs
index 4a21dc9..e209221 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs
@@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
37namespace OpenSim.Region.Framework.Scenes.Tests 37namespace OpenSim.Region.Framework.Scenes.Tests
38{ 38{
39 [TestFixture] 39 [TestFixture]
40 public class BorderTests 40 public class BorderTests : OpenSimTestCase
41 { 41 {
42 [Test] 42 [Test]
43 public void TestCross() 43 public void TestCross()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
index ea9fc93..766ce83 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common;
41namespace OpenSim.Region.Framework.Scenes.Tests 41namespace OpenSim.Region.Framework.Scenes.Tests
42{ 42{
43 [TestFixture, LongRunning] 43 [TestFixture, LongRunning]
44 public class EntityManagerTests 44 public class EntityManagerTests : OpenSimTestCase
45 { 45 {
46 static public Random random; 46 static public Random random;
47 SceneObjectGroup found; 47 SceneObjectGroup found;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
index d23c965..575a081 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
40namespace OpenSim.Region.Framework.Scenes.Tests 40namespace OpenSim.Region.Framework.Scenes.Tests
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class SceneGraphTests 43 public class SceneGraphTests : OpenSimTestCase
44 { 44 {
45 [Test] 45 [Test]
46 public void TestDuplicateObject() 46 public void TestDuplicateObject()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
index ab56f4e..2d831fa 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
@@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock;
41namespace OpenSim.Region.Framework.Scenes.Tests 41namespace OpenSim.Region.Framework.Scenes.Tests
42{ 42{
43 [TestFixture] 43 [TestFixture]
44 public class SceneManagerTests 44 public class SceneManagerTests : OpenSimTestCase
45 { 45 {
46 [Test] 46 [Test]
47 public void TestClose() 47 public void TestClose()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
index 5b334c6..a07d64c 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Threading; 31using System.Threading;
32using Nini.Config;
32using NUnit.Framework; 33using NUnit.Framework;
33using OpenMetaverse; 34using OpenMetaverse;
34using OpenSim.Framework; 35using OpenSim.Framework;
@@ -182,6 +183,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
182 /// <summary> 183 /// <summary>
183 /// Test deleting an object from a scene. 184 /// Test deleting an object from a scene.
184 /// </summary> 185 /// </summary>
186 /// <remarks>
187 /// This is the most basic form of delete. For all more sophisticated forms of derez (done asynchrnously
188 /// and where object can be taken to user inventory, etc.), see SceneObjectDeRezTests.
189 /// </remarks>
185 [Test] 190 [Test]
186 public void TestDeleteSceneObject() 191 public void TestDeleteSceneObject()
187 { 192 {
@@ -201,100 +206,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
201 } 206 }
202 207
203 /// <summary> 208 /// <summary>
204 /// Test deleting an object asynchronously
205 /// </summary>
206 [Test]
207 public void TestDeleteSceneObjectAsync()
208 {
209 TestHelpers.InMethod();
210 //log4net.Config.XmlConfigurator.Configure();
211
212 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
213
214 TestScene scene = new SceneHelpers().SetupScene();
215
216 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
217 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
218 sogd.Enabled = false;
219
220 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene);
221
222 IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
223 scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero);
224
225 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
226
227 Assert.That(retrievedPart, Is.Not.Null);
228
229 Assert.That(so.IsDeleted, Is.False);
230
231 sogd.InventoryDeQueueAndDelete();
232
233 Assert.That(so.IsDeleted, Is.True);
234
235 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
236 Assert.That(retrievedPart2, Is.Null);
237 }
238
239 /// <summary>
240 /// Test deleting an object asynchronously to user inventory.
241 /// </summary>
242// [Test]
243 public void TestDeleteSceneObjectAsyncToUserInventory()
244 {
245 TestHelpers.InMethod();
246 TestHelpers.EnableLogging();
247
248 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
249 string myObjectName = "Fred";
250
251 TestScene scene = new SceneHelpers().SetupScene();
252
253 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
254 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
255 sogd.Enabled = false;
256
257 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId);
258
259// Assert.That(
260// scene.CommsManager.UserAdminService.AddUser(
261// "Bob", "Hoskins", "test", "test@test.com", 1000, 1000, agentId),
262// Is.EqualTo(agentId));
263
264 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId);
265 InventoryFolderBase folder1
266 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1");
267
268 IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
269 scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID);
270
271 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
272
273 Assert.That(retrievedPart, Is.Not.Null);
274 Assert.That(so.IsDeleted, Is.False);
275
276 sogd.InventoryDeQueueAndDelete();
277
278 Assert.That(so.IsDeleted, Is.True);
279
280 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
281 Assert.That(retrievedPart2, Is.Null);
282
283// SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client);
284
285 InventoryItemBase retrievedItem
286 = UserInventoryHelpers.GetInventoryItem(
287 scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName);
288
289 // Check that we now have the taken part in our inventory
290 Assert.That(retrievedItem, Is.Not.Null);
291
292 // Check that the taken part has actually disappeared
293// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
294// Assert.That(retrievedPart, Is.Null);
295 }
296
297 /// <summary>
298 /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not 209 /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not
299 /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by 210 /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by
300 /// OpenSim. 211 /// OpenSim.
@@ -329,4 +240,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests
329 Assert.That(sog.Parts.Length, Is.EqualTo(2)); 240 Assert.That(sog.Parts.Length, Is.EqualTo(2));
330 } 241 }
331 } 242 }
332} 243} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
index 0076f41..c1522e7 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
@@ -33,22 +33,24 @@ using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications; 35using OpenSim.Framework.Communications;
36using OpenSim.Region.CoreModules.Framework.InventoryAccess;
36using OpenSim.Region.CoreModules.World.Permissions; 37using OpenSim.Region.CoreModules.World.Permissions;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
38using OpenSim.Tests.Common; 40using OpenSim.Tests.Common;
39using OpenSim.Tests.Common.Mock; 41using OpenSim.Tests.Common.Mock;
40 42
41namespace OpenSim.Region.Framework.Scenes.Tests 43namespace OpenSim.Region.Framework.Scenes.Tests
42{ 44{
43 /// <summary> 45 /// <summary>
44 /// Tests derez of scene objects by users. 46 /// Tests derez of scene objects.
45 /// </summary> 47 /// </summary>
46 /// <remarks> 48 /// <remarks>
47 /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. 49 /// This is at a level above the SceneObjectBasicTests, which act on the scene directly.
48 /// TODO: These tests are very incomplete - they only test for a few conditions. 50 /// TODO: These tests are incomplete - need to test more kinds of derez (e.g. return object).
49 /// </remarks> 51 /// </remarks>
50 [TestFixture] 52 [TestFixture]
51 public class SceneObjectDeRezTests 53 public class SceneObjectDeRezTests : OpenSimTestCase
52 { 54 {
53 /// <summary> 55 /// <summary>
54 /// Test deleting an object from a scene. 56 /// Test deleting an object from a scene.
@@ -76,14 +78,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests
76 = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); 78 = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero);
77 part.Name = "obj1"; 79 part.Name = "obj1";
78 scene.AddNewSceneObject(new SceneObjectGroup(part), false); 80 scene.AddNewSceneObject(new SceneObjectGroup(part), false);
81
79 List<uint> localIds = new List<uint>(); 82 List<uint> localIds = new List<uint>();
80 localIds.Add(part.LocalId); 83 localIds.Add(part.LocalId);
81
82 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); 84 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero);
85
86 // Check that object isn't deleted until we crank the sogd handle.
87 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
88 Assert.That(retrievedPart, Is.Not.Null);
89 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
90
83 sogd.InventoryDeQueueAndDelete(); 91 sogd.InventoryDeQueueAndDelete();
84 92
85 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); 93 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId);
86 Assert.That(retrievedPart, Is.Null); 94 Assert.That(retrievedPart2, Is.Null);
87 } 95 }
88 96
89 /// <summary> 97 /// <summary>
@@ -124,6 +132,67 @@ namespace OpenSim.Region.Framework.Scenes.Tests
124 // Object should still be in the scene. 132 // Object should still be in the scene.
125 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); 133 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
126 Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); 134 Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID));
127 } 135 }
136
137 /// <summary>
138 /// Test deleting an object asynchronously to user inventory.
139 /// </summary>
140 [Test]
141 public void TestDeleteSceneObjectAsyncToUserInventory()
142 {
143 TestHelpers.InMethod();
144// TestHelpers.EnableLogging();
145
146 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
147 string myObjectName = "Fred";
148
149 TestScene scene = new SceneHelpers().SetupScene();
150
151 IConfigSource configSource = new IniConfigSource();
152 IConfig config = configSource.AddConfig("Modules");
153 config.Set("InventoryAccessModule", "BasicInventoryAccessModule");
154 SceneHelpers.SetupSceneModules(
155 scene, configSource, new object[] { new BasicInventoryAccessModule() });
156
157 SceneHelpers.SetupSceneModules(scene, new object[] { });
158
159 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
160 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
161 sogd.Enabled = false;
162
163 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId);
164
165 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId);
166 InventoryFolderBase folder1
167 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1");
168
169 IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
170 scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID);
171
172 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
173
174 Assert.That(retrievedPart, Is.Not.Null);
175 Assert.That(so.IsDeleted, Is.False);
176
177 sogd.InventoryDeQueueAndDelete();
178
179 Assert.That(so.IsDeleted, Is.True);
180
181 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
182 Assert.That(retrievedPart2, Is.Null);
183
184// SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client);
185
186 InventoryItemBase retrievedItem
187 = UserInventoryHelpers.GetInventoryItem(
188 scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName);
189
190 // Check that we now have the taken part in our inventory
191 Assert.That(retrievedItem, Is.Not.Null);
192
193 // Check that the taken part has actually disappeared
194// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
195// Assert.That(retrievedPart, Is.Null);
196 }
128 } 197 }
129} \ No newline at end of file 198} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
index 0e525c9..9378e20 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
@@ -40,7 +40,7 @@ using log4net;
40namespace OpenSim.Region.Framework.Scenes.Tests 40namespace OpenSim.Region.Framework.Scenes.Tests
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class SceneObjectLinkingTests 43 public class SceneObjectLinkingTests : OpenSimTestCase
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
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
index e931859..1182c96 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
41 /// Basic scene object resize tests 41 /// Basic scene object resize tests
42 /// </summary> 42 /// </summary>
43 [TestFixture] 43 [TestFixture]
44 public class SceneObjectResizeTests 44 public class SceneObjectResizeTests : OpenSimTestCase
45 { 45 {
46 /// <summary> 46 /// <summary>
47 /// Test resizing an object 47 /// Test resizing an object
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
index d2361f8..a58e735 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
@@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
40namespace OpenSim.Region.Framework.Scenes.Tests 40namespace OpenSim.Region.Framework.Scenes.Tests
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class SceneObjectScriptTests 43 public class SceneObjectScriptTests : OpenSimTestCase
44 { 44 {
45 [Test] 45 [Test]
46 public void TestAddScript() 46 public void TestAddScript()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
index 6d255aa..abaa1d1 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
@@ -42,14 +42,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests
42 /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) 42 /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.)
43 /// </summary> 43 /// </summary>
44 [TestFixture] 44 [TestFixture]
45 public class SceneObjectSpatialTests 45 public class SceneObjectSpatialTests : OpenSimTestCase
46 { 46 {
47 TestScene m_scene; 47 TestScene m_scene;
48 UUID m_ownerId = TestHelpers.ParseTail(0x1); 48 UUID m_ownerId = TestHelpers.ParseTail(0x1);
49 49
50 [SetUp] 50 [SetUp]
51 public void SetUp() 51 public override void SetUp()
52 { 52 {
53 base.SetUp();
54
53 m_scene = new SceneHelpers().SetupScene(); 55 m_scene = new SceneHelpers().SetupScene();
54 } 56 }
55 57
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
index 742c769..8eb3191 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
42 /// Basic scene object status tests 42 /// Basic scene object status tests
43 /// </summary> 43 /// </summary>
44 [TestFixture] 44 [TestFixture]
45 public class SceneObjectStatusTests 45 public class SceneObjectStatusTests : OpenSimTestCase
46 { 46 {
47 private TestScene m_scene; 47 private TestScene m_scene;
48 private UUID m_ownerId = TestHelpers.ParseTail(0x1); 48 private UUID m_ownerId = TestHelpers.ParseTail(0x1);
@@ -78,6 +78,26 @@ namespace OpenSim.Region.Framework.Scenes.Tests
78 } 78 }
79 79
80 [Test] 80 [Test]
81 public void TestSetNonPhysicsVolumeDetectSinglePrim()
82 {
83 TestHelpers.InMethod();
84
85 m_scene.AddSceneObject(m_so1);
86
87 SceneObjectPart rootPart = m_so1.RootPart;
88 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
89
90 m_so1.ScriptSetVolumeDetect(true);
91
92// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
93 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom));
94
95 m_so1.ScriptSetVolumeDetect(false);
96
97 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
98 }
99
100 [Test]
81 public void TestSetPhysicsSinglePrim() 101 public void TestSetPhysicsSinglePrim()
82 { 102 {
83 TestHelpers.InMethod(); 103 TestHelpers.InMethod();
@@ -89,13 +109,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests
89 109
90 m_so1.ScriptSetPhysicsStatus(true); 110 m_so1.ScriptSetPhysicsStatus(true);
91 111
92// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags);
93 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); 112 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
94 113
95 m_so1.ScriptSetPhysicsStatus(false); 114 m_so1.ScriptSetPhysicsStatus(false);
96 115
97 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); 116 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
98 } 117 }
118
119 [Test]
120 public void TestSetPhysicsVolumeDetectSinglePrim()
121 {
122 TestHelpers.InMethod();
123
124 m_scene.AddSceneObject(m_so1);
125
126 SceneObjectPart rootPart = m_so1.RootPart;
127 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None));
128
129 m_so1.ScriptSetPhysicsStatus(true);
130 m_so1.ScriptSetVolumeDetect(true);
131
132 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics));
133
134 m_so1.ScriptSetVolumeDetect(false);
135
136 Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics));
137 }
99 138
100 [Test] 139 [Test]
101 public void TestSetPhysicsLinkset() 140 public void TestSetPhysicsLinkset()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
index 646e5fa..1cd8ae9 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
51 /// Scene presence animation tests 51 /// Scene presence animation tests
52 /// </summary> 52 /// </summary>
53 [TestFixture] 53 [TestFixture]
54 public class ScenePresenceAnimationTests 54 public class ScenePresenceAnimationTests : OpenSimTestCase
55 { 55 {
56 [Test] 56 [Test]
57 public void TestFlyingAnimation() 57 public void TestFlyingAnimation()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
index 1d1ff88..d80afd3 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
@@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock;
42namespace OpenSim.Region.Framework.Scenes.Tests 42namespace OpenSim.Region.Framework.Scenes.Tests
43{ 43{
44 [TestFixture] 44 [TestFixture]
45 public class ScenePresenceAutopilotTests 45 public class ScenePresenceAutopilotTests : OpenSimTestCase
46 { 46 {
47 private TestScene m_scene; 47 private TestScene m_scene;
48 48
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
index 493ab70..acaeb90 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
@@ -43,7 +43,7 @@ using System.Threading;
43namespace OpenSim.Region.Framework.Scenes.Tests 43namespace OpenSim.Region.Framework.Scenes.Tests
44{ 44{
45 [TestFixture] 45 [TestFixture]
46 public class ScenePresenceSitTests 46 public class ScenePresenceSitTests : OpenSimTestCase
47 { 47 {
48 private TestScene m_scene; 48 private TestScene m_scene;
49 private ScenePresence m_sp; 49 private ScenePresence m_sp;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index 37b5184..8dd1f3d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
49 /// Teleport tests in a standalone OpenSim 49 /// Teleport tests in a standalone OpenSim
50 /// </summary> 50 /// </summary>
51 [TestFixture] 51 [TestFixture]
52 public class ScenePresenceTeleportTests 52 public class ScenePresenceTeleportTests : OpenSimTestCase
53 { 53 {
54 [TestFixtureSetUp] 54 [TestFixtureSetUp]
55 public void FixtureInit() 55 public void FixtureInit()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
index ac3da1e..9d8eb0b 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
@@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
50 /// Scene presence tests 50 /// Scene presence tests
51 /// </summary> 51 /// </summary>
52 [TestFixture] 52 [TestFixture]
53 public class SceneTests 53 public class SceneTests : OpenSimTestCase
54 { 54 {
55 /// <summary> 55 /// <summary>
56 /// Very basic scene update test. Should become more elaborate with time. 56 /// Very basic scene update test. Should become more elaborate with time.
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
index a51e4e3..0b461f5 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
@@ -50,7 +50,7 @@ using OpenSim.Tests.Common.Mock;
50namespace OpenSim.Region.Framework.Tests 50namespace OpenSim.Region.Framework.Tests
51{ 51{
52 [TestFixture] 52 [TestFixture]
53 public class TaskInventoryTests 53 public class TaskInventoryTests : OpenSimTestCase
54 { 54 {
55 [Test] 55 [Test]
56 public void TestAddTaskInventoryItem() 56 public void TestAddTaskInventoryItem()
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
index 198e487..dd27294 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
@@ -38,7 +38,7 @@ using OpenSim.Tests.Common.Mock;
38namespace OpenSim.Region.Framework.Scenes.Tests 38namespace OpenSim.Region.Framework.Scenes.Tests
39{ 39{
40 [TestFixture] 40 [TestFixture]
41 public class UuidGathererTests 41 public class UuidGathererTests : OpenSimTestCase
42 { 42 {
43 protected IAssetService m_assetService; 43 protected IAssetService m_assetService;
44 protected UuidGatherer m_uuidGatherer; 44 protected UuidGatherer m_uuidGatherer;
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs
index 6d26075..6b5b40a 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/IGroupsServicesConnector.cs
@@ -36,7 +36,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
36 { 36 {
37 UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID); 37 UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID);
38 void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); 38 void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish);
39
40 /// <summary>
41 /// Get the group record.
42 /// </summary>
43 /// <returns></returns>
44 /// <param name='RequestingAgentID'>The UUID of the user making the request.</param>
45 /// <param name='GroupID'>
46 /// The ID of the record to retrieve.
47 /// GroupName may be specified instead, in which case this parameter will be UUID.Zero
48 /// </param>
49 /// <param name='GroupName'>
50 /// The name of the group to retrieve.
51 /// GroupID may be specified instead, in which case this parmeter will be null.
52 /// </param>
39 GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName); 53 GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName);
54
40 List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search); 55 List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search);
41 List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID); 56 List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID);
42 57
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
index ac638f1..c1bdacb 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
42 /// Basic groups module tests 42 /// Basic groups module tests
43 /// </summary> 43 /// </summary>
44 [TestFixture] 44 [TestFixture]
45 public class GroupsModuleTests 45 public class GroupsModuleTests : OpenSimTestCase
46 { 46 {
47 [Test] 47 [Test]
48 public void TestBasic() 48 public void TestBasic()
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
index d0c3ea5..1101851 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
@@ -54,13 +54,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
54 54
55 private bool m_debugEnabled = false; 55 private bool m_debugEnabled = false;
56 56
57 public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome | 57 public const GroupPowers DefaultEveryonePowers
58 GroupPowers.Accountable | 58 = GroupPowers.AllowSetHome
59 GroupPowers.JoinChat | 59 | GroupPowers.Accountable
60 GroupPowers.AllowVoiceChat | 60 | GroupPowers.JoinChat
61 GroupPowers.ReceiveNotices | 61 | GroupPowers.AllowVoiceChat
62 GroupPowers.StartProposal | 62 | GroupPowers.ReceiveNotices
63 GroupPowers.VoteOnProposal; 63 | GroupPowers.StartProposal
64 | GroupPowers.VoteOnProposal;
65
66 // Would this be cleaner as (GroupPowers)ulong.MaxValue?
67 public const GroupPowers DefaultOwnerPowers
68 = GroupPowers.Accountable
69 | GroupPowers.AllowEditLand
70 | GroupPowers.AllowFly
71 | GroupPowers.AllowLandmark
72 | GroupPowers.AllowRez
73 | GroupPowers.AllowSetHome
74 | GroupPowers.AllowVoiceChat
75 | GroupPowers.AssignMember
76 | GroupPowers.AssignMemberLimited
77 | GroupPowers.ChangeActions
78 | GroupPowers.ChangeIdentity
79 | GroupPowers.ChangeMedia
80 | GroupPowers.ChangeOptions
81 | GroupPowers.CreateRole
82 | GroupPowers.DeedObject
83 | GroupPowers.DeleteRole
84 | GroupPowers.Eject
85 | GroupPowers.FindPlaces
86 | GroupPowers.Invite
87 | GroupPowers.JoinChat
88 | GroupPowers.LandChangeIdentity
89 | GroupPowers.LandDeed
90 | GroupPowers.LandDivideJoin
91 | GroupPowers.LandEdit
92 | GroupPowers.LandEjectAndFreeze
93 | GroupPowers.LandGardening
94 | GroupPowers.LandManageAllowed
95 | GroupPowers.LandManageBanned
96 | GroupPowers.LandManagePasses
97 | GroupPowers.LandOptions
98 | GroupPowers.LandRelease
99 | GroupPowers.LandSetSale
100 | GroupPowers.ModerateChat
101 | GroupPowers.ObjectManipulate
102 | GroupPowers.ObjectSetForSale
103 | GroupPowers.ReceiveNotices
104 | GroupPowers.RemoveMember
105 | GroupPowers.ReturnGroupOwned
106 | GroupPowers.ReturnGroupSet
107 | GroupPowers.ReturnNonGroup
108 | GroupPowers.RoleProperties
109 | GroupPowers.SendNotices
110 | GroupPowers.SetLandingPoint
111 | GroupPowers.StartProposal
112 | GroupPowers.VoteOnProposal;
64 113
65 private bool m_connectorEnabled = false; 114 private bool m_connectorEnabled = false;
66 115
@@ -219,59 +268,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
219 param["AllowPublish"] = allowPublish == true ? 1 : 0; 268 param["AllowPublish"] = allowPublish == true ? 1 : 0;
220 param["MaturePublish"] = maturePublish == true ? 1 : 0; 269 param["MaturePublish"] = maturePublish == true ? 1 : 0;
221 param["FounderID"] = founderID.ToString(); 270 param["FounderID"] = founderID.ToString();
222 param["EveryonePowers"] = ((ulong)m_DefaultEveryonePowers).ToString(); 271 param["EveryonePowers"] = ((ulong)DefaultEveryonePowers).ToString();
223 param["OwnerRoleID"] = OwnerRoleID.ToString(); 272 param["OwnerRoleID"] = OwnerRoleID.ToString();
224 273 param["OwnersPowers"] = ((ulong)DefaultOwnerPowers).ToString();
225 // Would this be cleaner as (GroupPowers)ulong.MaxValue;
226 GroupPowers OwnerPowers = GroupPowers.Accountable
227 | GroupPowers.AllowEditLand
228 | GroupPowers.AllowFly
229 | GroupPowers.AllowLandmark
230 | GroupPowers.AllowRez
231 | GroupPowers.AllowSetHome
232 | GroupPowers.AllowVoiceChat
233 | GroupPowers.AssignMember
234 | GroupPowers.AssignMemberLimited
235 | GroupPowers.ChangeActions
236 | GroupPowers.ChangeIdentity
237 | GroupPowers.ChangeMedia
238 | GroupPowers.ChangeOptions
239 | GroupPowers.CreateRole
240 | GroupPowers.DeedObject
241 | GroupPowers.DeleteRole
242 | GroupPowers.Eject
243 | GroupPowers.FindPlaces
244 | GroupPowers.Invite
245 | GroupPowers.JoinChat
246 | GroupPowers.LandChangeIdentity
247 | GroupPowers.LandDeed
248 | GroupPowers.LandDivideJoin
249 | GroupPowers.LandEdit
250 | GroupPowers.LandEjectAndFreeze
251 | GroupPowers.LandGardening
252 | GroupPowers.LandManageAllowed
253 | GroupPowers.LandManageBanned
254 | GroupPowers.LandManagePasses
255 | GroupPowers.LandOptions
256 | GroupPowers.LandRelease
257 | GroupPowers.LandSetSale
258 | GroupPowers.ModerateChat
259 | GroupPowers.ObjectManipulate
260 | GroupPowers.ObjectSetForSale
261 | GroupPowers.ReceiveNotices
262 | GroupPowers.RemoveMember
263 | GroupPowers.ReturnGroupOwned
264 | GroupPowers.ReturnGroupSet
265 | GroupPowers.ReturnNonGroup
266 | GroupPowers.RoleProperties
267 | GroupPowers.SendNotices
268 | GroupPowers.SetLandingPoint
269 | GroupPowers.StartProposal
270 | GroupPowers.VoteOnProposal;
271 param["OwnersPowers"] = ((ulong)OwnerPowers).ToString();
272
273
274
275 274
276 Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param); 275 Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param);
277 276
@@ -612,8 +611,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
612 } 611 }
613 612
614 return Roles; 613 return Roles;
615
616
617 } 614 }
618 615
619 public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID) 616 public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID)
@@ -676,7 +673,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
676 } 673 }
677 674
678 return members; 675 return members;
679
680 } 676 }
681 677
682 public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) 678 public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID)
@@ -727,9 +723,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
727 values.Add(data); 723 values.Add(data);
728 } 724 }
729 } 725 }
730 return values;
731 726
727 return values;
732 } 728 }
729
733 public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) 730 public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID)
734 { 731 {
735 Hashtable param = new Hashtable(); 732 Hashtable param = new Hashtable();
@@ -737,7 +734,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
737 734
738 Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param); 735 Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param);
739 736
740
741 if (respData.Contains("error")) 737 if (respData.Contains("error"))
742 { 738 {
743 return null; 739 return null;
@@ -761,6 +757,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
761 757
762 return data; 758 return data;
763 } 759 }
760
764 public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) 761 public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket)
765 { 762 {
766 string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, ""); 763 string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, "");
@@ -777,8 +774,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
777 XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param); 774 XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param);
778 } 775 }
779 776
780
781
782 #endregion 777 #endregion
783 778
784 #region GroupSessionTracking 779 #region GroupSessionTracking
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
index 6120a81..709d389 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
@@ -46,6 +46,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
46{ 46{
47 public class XmlRpcInfo 47 public class XmlRpcInfo
48 { 48 {
49 public UUID item;
49 public UUID channel; 50 public UUID channel;
50 public string uri; 51 public string uri;
51 } 52 }
@@ -88,6 +89,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
88 return; 89 return;
89 90
90 scene.RegisterModuleInterface<IXmlRpcRouter>(this); 91 scene.RegisterModuleInterface<IXmlRpcRouter>(this);
92
93 IScriptModule scriptEngine = scene.RequestModuleInterface<IScriptModule>();
94 if ( scriptEngine != null )
95 {
96 scriptEngine.OnScriptRemoved += this.ScriptRemoved;
97 scriptEngine.OnObjectRemoved += this.ObjectRemoved;
98
99 }
91 } 100 }
92 101
93 public void RegionLoaded(Scene scene) 102 public void RegionLoaded(Scene scene)
@@ -120,22 +129,36 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
120 129
121 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) 130 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri)
122 { 131 {
123 if (!m_Channels.ContainsKey(itemID)) 132 if (!m_Enabled)
124 { 133 return;
125 XmlRpcInfo info = new XmlRpcInfo();
126 info.channel = channel;
127 info.uri = uri;
128 134
129 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( 135 m_log.InfoFormat("[XMLRPC GRID ROUTER]: New receiver Obj: {0} Ch: {1} ID: {2} URI: {3}",
130 "POST", m_ServerURI+"/RegisterChannel/", info); 136 objectID.ToString(), channel.ToString(), itemID.ToString(), uri);
131 137
132 if (!success) 138 XmlRpcInfo info = new XmlRpcInfo();
133 { 139 info.channel = channel;
134 m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); 140 info.uri = uri;
135 } 141 info.item = itemID;
142
143 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
144 "POST", m_ServerURI+"/RegisterChannel/", info);
136 145
137 m_Channels[itemID] = channel; 146 if (!success)
147 {
148 m_log.Error("[XMLRPC GRID ROUTER] Error contacting server");
138 } 149 }
150
151 m_Channels[itemID] = channel;
152
153 }
154
155 public void UnRegisterReceiver(string channelID, UUID itemID)
156 {
157 if (!m_Enabled)
158 return;
159
160 RemoveChannel(itemID);
161
139 } 162 }
140 163
141 public void ScriptRemoved(UUID itemID) 164 public void ScriptRemoved(UUID itemID)
@@ -143,10 +166,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
143 if (!m_Enabled) 166 if (!m_Enabled)
144 return; 167 return;
145 168
146 if (m_Channels.ContainsKey(itemID)) 169 RemoveChannel(itemID);
170
171 }
172
173 public void ObjectRemoved(UUID objectID)
174 {
175 // m_log.InfoFormat("[XMLRPC GRID ROUTER]: Object Removed {0}",objectID.ToString());
176 }
177
178 private bool RemoveChannel(UUID itemID)
179 {
180 if(!m_Channels.ContainsKey(itemID))
181 {
182 m_log.InfoFormat("[XMLRPC GRID ROUTER]: Attempted to unregister non-existing Item: {0}", itemID.ToString());
183 return false;
184 }
185
186 XmlRpcInfo info = new XmlRpcInfo();
187
188 info.channel = m_Channels[itemID];
189 info.item = itemID;
190 info.uri = "http://0.0.0.0:00";
191
192 if (info != null)
147 { 193 {
148 bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( 194 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
149 "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); 195 "POST", m_ServerURI+"/RemoveChannel/", info);
150 196
151 if (!success) 197 if (!success)
152 { 198 {
@@ -154,11 +200,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
154 } 200 }
155 201
156 m_Channels.Remove(itemID); 202 m_Channels.Remove(itemID);
203 return true;
157 } 204 }
158 } 205 return false;
159
160 public void ObjectRemoved(UUID objectID)
161 {
162 } 206 }
163 } 207 }
164} 208}
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
index 4bde52a..9d373ef 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
@@ -104,12 +104,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
104 } 104 }
105 } 105 }
106 106
107 public void UnRegisterReceiver(string channelID, UUID itemID)
108 {
109 }
110
107 public void ScriptRemoved(UUID itemID) 111 public void ScriptRemoved(UUID itemID)
108 { 112 {
113 System.Console.WriteLine("TEST Script Removed!");
109 } 114 }
110 115
111 public void ObjectRemoved(UUID objectID) 116 public void ObjectRemoved(UUID objectID)
112 { 117 {
118 System.Console.WriteLine("TEST Obj Removed!");
113 } 119 }
114 } 120 }
115} 121}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index 52ed846..a522277 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock;
48namespace OpenSim.Region.OptionalModules.World.NPC.Tests 48namespace OpenSim.Region.OptionalModules.World.NPC.Tests
49{ 49{
50 [TestFixture] 50 [TestFixture]
51 public class NPCModuleTests 51 public class NPCModuleTests : OpenSimTestCase
52 { 52 {
53 private TestScene m_scene; 53 private TestScene m_scene;
54 private AvatarFactoryModule m_afMod; 54 private AvatarFactoryModule m_afMod;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..4dd6264 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -105,12 +105,12 @@ public sealed class BSCharacter : BSPhysObject
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 107
108 // do actual create at taint time 108 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 109 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 110 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 111 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 112 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 114
115 SetPhysicalProperties(); 115 SetPhysicalProperties();
116 }); 116 });
@@ -124,7 +124,9 @@ public sealed class BSCharacter : BSPhysObject
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 125 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
127 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 128 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
129 PhysShape.Clear();
128 }); 130 });
129 } 131 }
130 132
@@ -165,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 167 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
166 168
167 // Do this after the object has been added to the world 169 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 170 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 171 PhysBody.ApplyCollisionMask();
170 (uint)CollisionFilterGroups.AvatarMask);
171 } 172 }
172 173
173 public override void RequestPhysicsterseUpdate() 174 public override void RequestPhysicsterseUpdate()
@@ -187,6 +188,11 @@ public sealed class BSCharacter : BSPhysObject
187 set { 188 set {
188 // When an avatar's size is set, only the height is changed. 189 // When an avatar's size is set, only the height is changed.
189 _size = value; 190 _size = value;
191 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
192 // replace with the default values.
193 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
194 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
195
190 ComputeAvatarScale(_size); 196 ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 197 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 198 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
@@ -194,15 +200,18 @@ public sealed class BSCharacter : BSPhysObject
194 200
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 201 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 202 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 203 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 204 {
205 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
206 UpdatePhysicalMassProperties(RawMass);
207 // Make sure this change appears as a property update event
208 BulletSimAPI.PushUpdate2(PhysBody.ptr);
209 }
199 }); 210 });
200 211
201 } 212 }
202 } 213 }
203 214
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 215 public override PrimitiveBaseShape Shape
207 { 216 {
208 set { BaseShape = value; } 217 set { BaseShape = value; }
@@ -236,7 +245,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 245 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 247 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 248 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
240 }); 250 });
241 } 251 }
242 public override void ZeroAngularMotion(bool inTaintTime) 252 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +255,13 @@ public sealed class BSCharacter : BSPhysObject
245 255
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 256 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 257 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 258 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 259 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 260 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 261 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
262 // The next also get rid of applied linear force but the linear velocity is untouched.
263 BulletSimAPI.ClearForces2(PhysBody.ptr);
264 }
252 }); 265 });
253 } 266 }
254 267
@@ -273,7 +286,8 @@ public sealed class BSCharacter : BSPhysObject
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 286 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 287 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 288 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 289 if (PhysBody.HasPhysicalBody)
290 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
277 }); 291 });
278 } 292 }
279 } 293 }
@@ -297,6 +311,15 @@ public sealed class BSCharacter : BSPhysObject
297 { 311 {
298 bool ret = false; 312 bool ret = false;
299 313
314 // TODO: check for out of bounds
315 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
316 {
317 // The character is out of the known/simulated area.
318 // Upper levels of code will handle the transition to other areas so, for
319 // the time, we just ignore the position.
320 return ret;
321 }
322
300 // If below the ground, move the avatar up 323 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 324 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
302 if (Position.Z < terrainHeight) 325 if (Position.Z < terrainHeight)
@@ -307,7 +330,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 330 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 331 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 332 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 333 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 334 if (Position.Z < waterHeight)
312 { 335 {
313 _position.Z = waterHeight; 336 _position.Z = waterHeight;
@@ -315,7 +338,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 338 }
316 } 339 }
317 340
318 // TODO: check for out of bounds
319 return ret; 341 return ret;
320 } 342 }
321 343
@@ -332,7 +354,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 354 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 355 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 356 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 357 if (PhysBody.HasPhysicalBody)
358 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
336 }); 359 });
337 ret = true; 360 ret = true;
338 } 361 }
@@ -359,7 +382,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 382 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 383 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 384 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 385 if (PhysBody.HasPhysicalBody)
386 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
363 }); 387 });
364 } 388 }
365 } 389 }
@@ -398,7 +422,8 @@ public sealed class BSCharacter : BSPhysObject
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 422 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 { 423 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 424 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 425 if (PhysBody.HasPhysicalBody)
426 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 } 427 }
403 } 428 }
404 else 429 else
@@ -406,7 +431,8 @@ public sealed class BSCharacter : BSPhysObject
406 if (_currentFriction != PhysicsScene.Params.avatarFriction) 431 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 { 432 {
408 _currentFriction = PhysicsScene.Params.avatarFriction; 433 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 434 if (PhysBody.HasPhysicalBody)
435 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 } 436 }
411 } 437 }
412 _velocity = value; 438 _velocity = value;
@@ -443,8 +469,11 @@ public sealed class BSCharacter : BSPhysObject
443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 469 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 470 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
445 { 471 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 472 if (PhysBody.HasPhysicalBody)
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 473 {
474 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
475 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
476 }
448 }); 477 });
449 } 478 }
450 } 479 }
@@ -517,10 +546,13 @@ public sealed class BSCharacter : BSPhysObject
517 _floatOnWater = value; 546 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 547 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 548 {
520 if (_floatOnWater) 549 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 550 {
522 else 551 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 552 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
553 else
554 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
555 }
524 }); 556 });
525 } 557 }
526 } 558 }
@@ -553,7 +585,8 @@ public sealed class BSCharacter : BSPhysObject
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 585 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 586 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 587 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 588 if (PhysBody.HasPhysicalBody)
589 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
557 } 590 }
558 } 591 }
559 592
@@ -599,7 +632,8 @@ public sealed class BSCharacter : BSPhysObject
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() 632 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 633 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 634 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 635 if (PhysBody.HasPhysicalBody)
636 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
603 }); 637 });
604 } 638 }
605 else 639 else
@@ -616,9 +650,6 @@ public sealed class BSCharacter : BSPhysObject
616 650
617 private void ComputeAvatarScale(OMV.Vector3 size) 651 private void ComputeAvatarScale(OMV.Vector3 size)
618 { 652 {
619 // The 'size' given by the simulator is the mid-point of the avatar
620 // and X and Y are unspecified.
621
622 OMV.Vector3 newScale = size; 653 OMV.Vector3 newScale = size;
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 654 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 655 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
@@ -677,7 +708,7 @@ public sealed class BSCharacter : BSPhysObject
677 } 708 }
678 709
679 // Tell the linkset about value changes 710 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 711 Linkset.UpdateProperties(this, true);
681 712
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 713 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 714 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 65fac00..6b1e304 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -57,7 +57,7 @@ public abstract class BSConstraint : IDisposable
57 if (m_enabled) 57 if (m_enabled)
58 { 58 {
59 m_enabled = false; 59 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero) 60 if (m_constraint.HasPhysicalConstraint)
61 { 61 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
@@ -65,7 +65,7 @@ public abstract class BSConstraint : IDisposable
65 m_body1.ID, m_body1.ptr.ToString("X"), 65 m_body1.ID, m_body1.ptr.ToString("X"),
66 m_body2.ID, m_body2.ptr.ToString("X"), 66 m_body2.ID, m_body2.ptr.ToString("X"),
67 success); 67 success);
68 m_constraint.ptr = System.IntPtr.Zero; 68 m_constraint.Clear();
69 } 69 }
70 } 70 }
71 } 71 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 23ef052..b073555 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -65,7 +65,7 @@ public sealed class BSConstraint6Dof : BSConstraint
65 m_world = world; 65 m_world = world;
66 m_body1 = obj1; 66 m_body1 = obj1;
67 m_body2 = obj2; 67 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
@@ -83,7 +83,7 @@ public sealed class BSConstraint6Dof : BSConstraint
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), 84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
86 if (m_constraint.ptr == IntPtr.Zero) 86 if (!m_constraint.HasPhysicalConstraint)
87 { 87 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 89 LogHeader, obj1.ID, obj2.ID);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..5887249 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -24,30 +24,17 @@
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 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * call the BulletSim system. 29 * of Creative Commons Attribution-Share Alike 3.0
30 */ 30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
32 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
33 * ODEPrim.cs contains methods dealing with Prim editing, Prim
34 * characteristics and Kinetic motion.
35 * ODEDynamics.cs contains methods dealing with Prim Physical motion
36 * (dynamics) and the associated settings. Old Linear and angular
37 * motors for dynamic motion have been replace with MoveLinear()
38 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
39 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
40 * switch between 'VEHICLE' parameter use and general dynamics
41 * settings use.
42 */ 31 */
43 32
44using System; 33using System;
45using System.Collections.Generic; 34using System.Collections.Generic;
46using System.Reflection; 35using System.Reflection;
47using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
48using log4net;
49using OpenMetaverse; 37using OpenMetaverse;
50using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager; 38using OpenSim.Region.Physics.Manager;
52 39
53namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
@@ -80,10 +67,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 67 private Quaternion m_referenceFrame = Quaternion.Identity;
81 68
82 // Linear properties 69 // Linear properties
70 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 71 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
87 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 74 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 75 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 76 private float m_linearMotorTimescale = 0;
@@ -93,13 +80,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 80 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 81
95 //Angular properties 82 //Angular properties
83 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 85 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
101 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
102 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 90 private Vector3 m_lastAngularVelocity = Vector3.Zero;
103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
104 92
105 //Deflection properties 93 //Deflection properties
@@ -124,8 +112,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. 112 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
125 113
126 //Attractor properties 114 //Attractor properties
127 private float m_verticalAttractionEfficiency = 1.0f; // damped 115 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 116 private float m_verticalAttractionEfficiency = 1.0f; // damped
117 private float m_verticalAttractionCutoff = 500f; // per the documentation
118 // Timescale > cutoff means no vert attractor.
119 private float m_verticalAttractionTimescale = 510f;
129 120
130 public BSDynamics(BSScene myScene, BSPrim myPrim) 121 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 { 122 {
@@ -137,7 +128,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
137 // Return 'true' if this vehicle is doing vehicle things 128 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive 129 public bool IsActive
139 { 130 {
140 get { return Type != Vehicle.TYPE_NONE; } 131 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; }
141 } 132 }
142 133
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
@@ -152,13 +143,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 143 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 144 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 145 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 146 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
147 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 148 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 149 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 150 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
151 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 152 break;
160 case Vehicle.BANKING_EFFICIENCY: 153 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 154 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 155 break;
163 case Vehicle.BANKING_MIX: 156 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 157 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 160 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 161 break;
169 case Vehicle.BUOYANCY: 162 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 163 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
171 break; 164 break;
172 case Vehicle.HOVER_EFFICIENCY: 165 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 166 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 167 break;
175 case Vehicle.HOVER_HEIGHT: 168 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 169 m_VhoverHeight = pValue;
@@ -185,33 +178,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 178 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 179 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 180 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 181 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
182 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 183 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 184 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 185 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
186 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 187 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 188 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 189 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
190 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 191 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 192 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 193 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
194 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 195 break;
199 196
200 // These are vector properties but the engine lets you use a single float value to 197 // These are vector properties but the engine lets you use a single float value to
201 // set all of the components to the same value 198 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 199 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 200 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
201 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 202 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 203 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 204 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 205 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 206 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 207 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 208 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
209 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 210 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 211 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 212 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 213 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
214 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 215 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 216 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +227,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 227 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 228 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
230 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 231 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 232 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 233 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 234 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 235 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 236 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 237 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 238 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 239 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 240 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 241 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
242 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 243 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 244 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 245 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 246 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
247 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 248 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 249 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 250 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 306 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 307 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 308 m_VehicleBuoyancy = 0;
306 309
307 m_linearDeflectionEfficiency = 1; 310 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 311 m_linearDeflectionTimescale = 1;
309 312
@@ -319,6 +322,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 322
320 m_referenceFrame = Quaternion.Identity; 323 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 324 m_flags = (VehicleFlag)0;
325
322 break; 326 break;
323 327
324 case Vehicle.TYPE_SLED: 328 case Vehicle.TYPE_SLED:
@@ -351,10 +355,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 355 m_bankingMix = 1;
352 356
353 m_referenceFrame = Quaternion.Identity; 357 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 359 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 360 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 361 | VehicleFlag.HOVER_UP_ONLY);
362 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
363 | VehicleFlag.LIMIT_ROLL_ONLY
364 | VehicleFlag.LIMIT_MOTOR_UP);
365
358 break; 366 break;
359 case Vehicle.TYPE_CAR: 367 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 368 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +506,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 506 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 507 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 508 m_bankingTimescale = 5;
509
501 m_referenceFrame = Quaternion.Identity; 510 m_referenceFrame = Quaternion.Identity;
502 511
503 m_referenceFrame = Quaternion.Identity; 512 m_referenceFrame = Quaternion.Identity;
@@ -510,6 +519,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 519 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 520 break;
512 } 521 }
522
523 // Update any physical parameters based on this type.
524 Refresh();
525
526 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
527 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
528 1f);
529 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
530
531 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
532 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
533 1f);
534 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
535
536 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
537 BSMotor.Infinite, BSMotor.InfiniteVector,
538 m_verticalAttractionEfficiency);
539 // Z goes away and we keep X and Y
540 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
541 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
513 } 542 }
514 543
515 // Some of the properties of this prim may have changed. 544 // Some of the properties of this prim may have changed.
@@ -518,13 +547,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 547 {
519 if (IsActive) 548 if (IsActive)
520 { 549 {
521 // Friction effects are handled by this vehicle code 550 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 551 m_vehicleMass = Prim.Linkset.LinksetMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); 552
524 553 // Friction affects are handled by this vehicle code
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 554 float friction = 0f;
526 555 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 556
557 // Moderate angular movement introduced by Bullet.
558 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
559 // Maybe compute linear and angular factor and damping from params.
560 float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
561 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
562
563 // Vehicles report collision events so we know when it's on the ground
564 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
565
566 // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
567 // Vector3 localInertia = new Vector3(1f, 1f, 1f);
568 // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
569 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
570 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
571 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
572
573 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
574 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
575 }
576 else
577 {
578 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 579 }
529 } 580 }
530 581
@@ -546,116 +597,294 @@ namespace OpenSim.Region.Physics.BulletSPlugin
546 Refresh(); 597 Refresh();
547 } 598 }
548 599
600 #region Known vehicle value functions
601 // Vehicle physical parameters that we buffer from constant getting and setting.
602 // The "m_known*" variables are initialized to 'null', fetched only if referenced
603 // and stored back into the physics engine only if updated.
604 // This does two things: 1) saves continuious calls into unmanaged code, and
605 // 2) signals when a physics property update must happen back to the simulator
606 // to update values modified for the vehicle.
607 private int m_knownChanged;
608 private float? m_knownTerrainHeight;
609 private float? m_knownWaterLevel;
610 private Vector3? m_knownPosition;
611 private Vector3? m_knownVelocity;
612 private Vector3 m_knownForce;
613 private Quaternion? m_knownOrientation;
614 private Vector3? m_knownRotationalVelocity;
615 private Vector3 m_knownRotationalForce;
616 private float? m_knownForwardSpeed;
617
618 private const int m_knownChangedPosition = 1 << 0;
619 private const int m_knownChangedVelocity = 1 << 1;
620 private const int m_knownChangedForce = 1 << 2;
621 private const int m_knownChangedOrientation = 1 << 3;
622 private const int m_knownChangedRotationalVelocity = 1 << 4;
623 private const int m_knownChangedRotationalForce = 1 << 5;
624
625 private void ForgetKnownVehicleProperties()
626 {
627 m_knownTerrainHeight = null;
628 m_knownWaterLevel = null;
629 m_knownPosition = null;
630 m_knownVelocity = null;
631 m_knownForce = Vector3.Zero;
632 m_knownOrientation = null;
633 m_knownRotationalVelocity = null;
634 m_knownRotationalForce = Vector3.Zero;
635 m_knownForwardSpeed = null;
636 m_knownChanged = 0;
637 }
638 private void PushKnownChanged()
639 {
640 if (m_knownChanged != 0)
641 {
642 if ((m_knownChanged & m_knownChangedPosition) != 0)
643 Prim.ForcePosition = VehiclePosition;
644 if ((m_knownChanged & m_knownChangedOrientation) != 0)
645 Prim.ForceOrientation = VehicleOrientation;
646 if ((m_knownChanged & m_knownChangedVelocity) != 0)
647 {
648 Prim.ForceVelocity = VehicleVelocity;
649 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
650 }
651 if ((m_knownChanged & m_knownChangedForce) != 0)
652 Prim.AddForce((Vector3)m_knownForce, false, true);
653
654 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
655 {
656 Prim.ForceRotationalVelocity = VehicleRotationalVelocity;
657 // Fake out Bullet by making it think the velocity is the same as last time.
658 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity);
659 }
660 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
661 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
662
663 // If we set one of the values (ie, the physics engine didn't do it) we must force
664 // an UpdateProperties event to send the changes up to the simulator.
665 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
666 }
667 m_knownChanged = 0;
668 }
669
670 // Since the computation of terrain height can be a little involved, this routine
671 // is used ot fetch the height only once for each vehicle simulation step.
672 private float GetTerrainHeight(Vector3 pos)
673 {
674 if (m_knownTerrainHeight == null)
675 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
676 return (float)m_knownTerrainHeight;
677 }
678
679 // Since the computation of water level can be a little involved, this routine
680 // is used ot fetch the level only once for each vehicle simulation step.
681 private float GetWaterLevel(Vector3 pos)
682 {
683 if (m_knownWaterLevel == null)
684 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
685 return (float)m_knownWaterLevel;
686 }
687
688 private Vector3 VehiclePosition
689 {
690 get
691 {
692 if (m_knownPosition == null)
693 m_knownPosition = Prim.ForcePosition;
694 return (Vector3)m_knownPosition;
695 }
696 set
697 {
698 m_knownPosition = value;
699 m_knownChanged |= m_knownChangedPosition;
700 }
701 }
702
703 private Quaternion VehicleOrientation
704 {
705 get
706 {
707 if (m_knownOrientation == null)
708 m_knownOrientation = Prim.ForceOrientation;
709 return (Quaternion)m_knownOrientation;
710 }
711 set
712 {
713 m_knownOrientation = value;
714 m_knownChanged |= m_knownChangedOrientation;
715 }
716 }
717
718 private Vector3 VehicleVelocity
719 {
720 get
721 {
722 if (m_knownVelocity == null)
723 m_knownVelocity = Prim.ForceVelocity;
724 return (Vector3)m_knownVelocity;
725 }
726 set
727 {
728 m_knownVelocity = value;
729 m_knownChanged |= m_knownChangedVelocity;
730 }
731 }
732
733 private void VehicleAddForce(Vector3 aForce)
734 {
735 m_knownForce += aForce;
736 m_knownChanged |= m_knownChangedForce;
737 }
738
739 private Vector3 VehicleRotationalVelocity
740 {
741 get
742 {
743 if (m_knownRotationalVelocity == null)
744 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
745 return (Vector3)m_knownRotationalVelocity;
746 }
747 set
748 {
749 m_knownRotationalVelocity = value;
750 m_knownChanged |= m_knownChangedRotationalVelocity;
751 }
752 }
753 private void VehicleAddAngularForce(Vector3 aForce)
754 {
755 m_knownRotationalForce += aForce;
756 m_knownChanged |= m_knownChangedRotationalForce;
757 }
758 private float VehicleForwardSpeed
759 {
760 get
761 {
762 if (m_knownForwardSpeed == null)
763 m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X;
764 return (float)m_knownForwardSpeed;
765 }
766 }
767
768 #endregion // Known vehicle value functions
769
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 770 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 771 internal void Step(float pTimestep)
551 { 772 {
552 if (!IsActive) return; 773 if (!IsActive) return;
553 774
554 // DEBUG 775 ForgetKnownVehicleProperties();
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564 776
565 MoveLinear(pTimestep); 777 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 778 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 779
571 LimitRotation(pTimestep); 780 LimitRotation(pTimestep);
572 781
573 // remember the position so next step we can limit absolute movement effects 782 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 783 m_lastPositionVector = VehiclePosition;
575 784
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 785 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 786 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 787 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), 788
580 Prim.Inertia,
581 m_vehicleMass
582 );
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 789 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 790 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
585 }// end Step 791 }
586 792
587 // Apply the effect of the linear motor. 793 // Apply the effect of the linear motor and other linear motions (like hover and float).
588 // Also does hover and float.
589 private void MoveLinear(float pTimestep) 794 private void MoveLinear(float pTimestep)
590 { 795 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 796 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
594 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
599 797
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 798 // The movement computed in the linear motor is relative to the vehicle
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; 799 // coordinates. Rotate the movement to world coordinates.
602 m_lastLinearVelocityVector += addAmount; 800 linearMotorContribution *= VehicleOrientation;
603 801
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 802 // ==================================================================
605 m_linearMotorDirection *= (1f - decayFactor); 803 // Buoyancy: force to overcome gravity.
804 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
805 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
806 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
606 807
607 // Rotate new object velocity from vehicle relative to world coordinates 808 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 809
610 // Apply friction for next time 810 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 811
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 812 ComputeLinearBlockingEndPoint(pTimestep);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
617 }
618 else
619 {
620 // if what remains of direction is very small, zero it.
621 m_linearMotorDirection = Vector3.Zero;
622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624 813
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 814 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
626 }
627 815
628 // m_newVelocity is velocity computed from linear motor in world coordinates 816 // ==================================================================
817 Vector3 newVelocity = linearMotorContribution
818 + terrainHeightContribution
819 + hoverContribution
820 + limitMotorUpContribution;
629 821
630 // Gravity and Buoyancy 822 Vector3 newForce = buoyancyContribution;
631 // There is some gravity, make a gravity force vector that is applied after object velocity. 823
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 824 // If not changing some axis, reduce out velocity
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 825 if ((m_flags & (VehicleFlag.NO_X)) != 0)
826 newVelocity.X = 0;
827 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
828 newVelocity.Y = 0;
829 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
830 newVelocity.Z = 0;
634 831
635 /* 832 // ==================================================================
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 833 // Clamp high or low velocities
637 // Preserve the current Z velocity 834 float newVelocityLengthSq = newVelocity.LengthSquared();
638 Vector3 vel_now = m_prim.Velocity; 835 // if (newVelocityLengthSq > 1e6f)
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 836 if (newVelocityLengthSq > 1000f)
640 */ 837 {
838 newVelocity /= newVelocity.Length();
839 newVelocity *= 1000f;
840 }
841 // else if (newVelocityLengthSq < 1e-6f)
842 else if (newVelocityLengthSq < 0.001f)
843 newVelocity = Vector3.Zero;
844
845 // ==================================================================
846 // Stuff new linear velocity into the vehicle.
847 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
848 VehicleVelocity = newVelocity;
849
850 // Other linear forces are applied as forces.
851 Vector3 totalDownForce = newForce * m_vehicleMass;
852 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
853 {
854 VehicleAddForce(totalDownForce);
855 }
856
857 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
858 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
859 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
860 Prim.LocalID,
861 linearMotorContribution, terrainHeightContribution, hoverContribution,
862 limitMotorUpContribution, buoyancyContribution
863 );
641 864
642 Vector3 pos = Prim.ForcePosition; 865 } // end MoveLinear()
643// 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);
644 866
867 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
868 {
869 Vector3 ret = Vector3.Zero;
645 // If below the terrain, move us above the ground a little. 870 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 871 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 872 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
650 // if (rotatedSize.Z < terrainHeight)
651 if (pos.Z < terrainHeight)
652 { 873 {
653 pos.Z = terrainHeight + 2; 874 // TODO: correct position by applying force rather than forcing position.
654 Prim.ForcePosition = pos; 875 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 876 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
877 VehiclePosition = newPosition;
878 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
879 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 880 }
881 return ret;
882 }
883
884 public Vector3 ComputeLinearHover(float pTimestep)
885 {
886 Vector3 ret = Vector3.Zero;
657 887
658 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 888 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 889 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 890 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +892,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 892 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 893 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 894 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 895 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 896 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 897 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 898 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 899 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 900 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 901 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 902 {
@@ -677,45 +906,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 906 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 907 {
679 // If body is already heigher, use its height as target height 908 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 909 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 910 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 911 }
912
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 913 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 914 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 915 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 916 {
917 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 918 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 919 VehiclePosition = pos;
689 } 920 }
690 } 921 }
691 else 922 else
692 { 923 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 924 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 925 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 926 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
696 // Replace Vertical speed with correction figure if significant 927
697 if (Math.Abs(verticalError) > 0.01f) 928 // TODO: implement m_VhoverEfficiency correctly
698 { 929 if (Math.Abs(verticalError) > m_VhoverEfficiency)
699 m_newVelocity.Z += verticalCorrectionVelocity;
700 //KF: m_VhoverEfficiency is not yet implemented
701 }
702 else if (verticalError < -0.01)
703 {
704 m_newVelocity.Z -= verticalCorrectionVelocity;
705 }
706 else
707 { 930 {
708 m_newVelocity.Z = 0f; 931 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
709 } 932 }
710 } 933 }
711 934
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 935 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
936 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
713 } 937 }
714 938
939 return ret;
940 }
941
942 public bool ComputeLinearBlockingEndPoint(float pTimestep)
943 {
944 bool changed = false;
945
946 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 947 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 948 if (m_BlockingEndPoint != Vector3.Zero)
717 { 949 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 950 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 951 {
721 pos.X -= posChange.X + 1; 952 pos.X -= posChange.X + 1;
@@ -743,233 +974,110 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 974 }
744 if (changed) 975 if (changed)
745 { 976 {
746 Prim.ForcePosition = pos; 977 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 978 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 979 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 980 }
750 } 981 }
982 return changed;
983 }
751 984
752 #region downForce 985 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 986 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
987 // used with conjunction with banking: the strength of the banking will decay when the
988 // vehicle no longer experiences collisions. The decay timescale is the same as
989 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
990 // when they are in mid jump.
991 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
992 // This is just using the ground and a general collision check. Should really be using
993 // a downward raycast to find what is below.
994 public Vector3 ComputeLinearMotorUp(float pTimestep)
995 {
996 Vector3 ret = Vector3.Zero;
997 float distanceAboveGround = 0f;
754 998
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 999 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1000 {
757 // If the vehicle is motoring into the sky, get it going back down. 1001 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
758 // Is this an angular force or both linear and angular?? 1002 distanceAboveGround = VehiclePosition.Z - targetHeight;
759 float distanceAboveGround = pos.Z - terrainHeight; 1003 // Not colliding if the vehicle is off the ground
760 if (distanceAboveGround > 2f) 1004 if (!Prim.IsColliding)
761 { 1005 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 1006 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1007 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1008 ret = new Vector3(0, 0, -distanceAboveGround);
765 } 1009 }
766 // TODO: this calculation is all wrong. From the description at 1010 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1011 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1012 // has a decay factor. This says this force should
769 // be computed with a motor. 1013 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1014 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce);
772 }
773 #endregion // downForce
774
775 // If not changing some axis, reduce out velocity
776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
777 m_newVelocity.X = 0;
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
779 m_newVelocity.Y = 0;
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
781 m_newVelocity.Z = 0;
782
783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
785 {
786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
788 } 1015 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f) 1016 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
790 m_newVelocity = Vector3.Zero; 1017 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
791 1018 return ret;
792 // Stuff new linear velocity into the vehicle 1019 }
793 Prim.ForceVelocity = m_newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
795
796 Vector3 totalDownForce = downForce + grav;
797 if (totalDownForce != Vector3.Zero)
798 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
802
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
805
806 } // end MoveLinear()
807 1020
808 // ======================================================================= 1021 // =======================================================================
1022 // =======================================================================
809 // Apply the effect of the angular motor. 1023 // Apply the effect of the angular motor.
1024 // The 'contribution' is how much angular correction velocity each function wants.
1025 // All the contributions are added together and the resulting velocity is
1026 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1027 private void MoveAngular(float pTimestep)
811 { 1028 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1029 // The user wants how many radians per second angular change?
813 // m_angularMotorApply // application frame counter 1030 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down) 1031
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 1032 // ==================================================================
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 1033 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
817 // m_angularFrictionTimescale // body angular velocity decay rate 1034 // This flag prevents linear deflection parallel to world z-axis. This is useful
818 // m_lastAngularVelocity // what was last applied to body 1035 // for preventing ground vehicles with large linear deflection, like bumper cars,
819 1036 // from climbing their linear deflection into the sky.
820 if (m_angularMotorDirection.LengthSquared() > 0.0001) 1037 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
821 { 1038 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
822 Vector3 origVel = m_angularMotorVelocity;
823 Vector3 origDir = m_angularMotorDirection;
824
825 // new velocity += error / ( time to get there / step interval)
826 // requested direction - current vehicle direction
827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
828 // decay requested direction
829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
830
831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
833 }
834 else
835 { 1039 {
836 m_angularMotorVelocity = Vector3.Zero; 1040 angularMotorContribution.X = 0f;
1041 angularMotorContribution.Y = 0f;
1042 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
837 } 1043 }
838 1044
839 #region Vertical attactor 1045 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
840
841 Vector3 vertattr = Vector3.Zero;
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
847 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
849 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
851
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
853
854 // Create a vector of the vehicle "up" in world coordinates
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
861
862 // Error is 0 (no error) to +/- 2 (max error)
863 if (verticalError.Z < 0.0f)
864 {
865 verticalError.X = 2.0f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y;
867 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
873 // Z is not changed.
874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877 1046
878 // scaling appears better usingsquare-law 1047 Vector3 deflectionContribution = ComputeAngularDeflection();
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
881 vertattr.X += bounce * angularVelocity.X;
882 vertattr.Y += bounce * angularVelocity.Y;
883 1048
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 1049 Vector3 bankingContribution = ComputeAngularBanking();
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
886 1050
887 } 1051 // ==================================================================
888 #endregion // Vertical attactor 1052 m_lastVertAttractor = verticalAttractionContribution;
889 1053
890 #region Deflection 1054 m_lastAngularVelocity = angularMotorContribution
1055 + verticalAttractionContribution
1056 + deflectionContribution
1057 + bankingContribution;
891 1058
892 if (m_angularDeflectionEfficiency != 0) 1059 // ==================================================================
1060 // Apply the correction velocity.
1061 // TODO: Should this be applied as an angular force (torque)?
1062 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
893 { 1063 {
894 // Compute a scaled vector that points in the preferred axis (X direction) 1064 VehicleRotationalVelocity = m_lastAngularVelocity;
895 Vector3 scaledDefaultDirection =
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
897 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
898 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900
901 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct.
907 deflection = Vector3.Zero;
908 }
909
910 #endregion
911
912 #region Banking
913 1065
914 if (m_bankingEfficiency != 0) 1066 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1067 Prim.LocalID,
1068 angularMotorContribution, verticalAttractionContribution,
1069 bankingContribution, deflectionContribution,
1070 m_lastAngularVelocity
1071 );
1072 }
1073 else
915 { 1074 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1075 // The vehicle is not adding anything angular wise.
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1076 VehicleRotationalVelocity = Vector3.Zero;
918 //Changes which way it banks in and out of turns 1077 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
919
920 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
922 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative!
924
925 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0)
927 {
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 {
930 Vector3 axisAngle;
931 float angle;
932 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
933 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
934 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
935 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
936 else
937 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
938 }*/
939 }
940 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 {
945 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix)
947 angVelZ = mix;
948 else if(angVelZ < -mix)
949 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
952 if (bankingRot.X > 3)
953 bankingRot.X = 3;
954 else if (bankingRot.X < -3)
955 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot;
958 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
962 } 1078 }
963 1079
964 #endregion 1080 // ==================================================================
965
966 m_lastVertAttractor = vertattr;
967
968 // Sum velocities
969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
970
971 #region Linear Motor Offset
972
973 //Offset section 1081 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1082 if (m_linearMotorOffset != Vector3.Zero)
975 { 1083 {
@@ -985,8 +1093,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1093 //
986 // The torque created is the linear velocity crossed with the offset 1094 // The torque created is the linear velocity crossed with the offset
987 1095
988 // NOTE: this computation does should be in the linear section 1096 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1097 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1098 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1099 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1100 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1103,175 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1103 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1104 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1105 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1106
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1107 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1108 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1109 }
1002 1110
1003 #endregion 1111 }
1112 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1113 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1114 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1115 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1116 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1117 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1118 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1119 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1120 public Vector3 ComputeAngularVerticalAttraction()
1121 {
1122 Vector3 ret = Vector3.Zero;
1004 1123
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1124 // If vertical attaction timescale is reasonable
1125 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1006 { 1126 {
1007 m_lastAngularVelocity.X = 0; 1127 // Take a vector pointing up and convert it from world to vehicle relative coords.
1008 m_lastAngularVelocity.Y = 0; 1128 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1129
1130 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1131 // is now:
1132 // leaning to one side: rotated around the X axis with the Y value going
1133 // from zero (nearly straight up) to one (completely to the side)) or
1134 // leaning front-to-back: rotated around the Y axis with the value of X being between
1135 // zero and one.
1136 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1137
1138 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1139 if (verticalError.Z < 0f)
1140 {
1141 verticalError.X = 2f - verticalError.X;
1142 verticalError.Y = 2f - verticalError.Y;
1143 }
1144
1145 // Y error means needed rotation around X axis and visa versa.
1146 ret.X = verticalError.Y;
1147 ret.Y = - verticalError.X;
1148 ret.Z = 0f;
1149
1150 // Scale the correction force by how far we're off from vertical.
1151 // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over.
1152 float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f);
1153 float vertForce = 1f / clampedSqrZError;
1154
1155 ret *= vertForce;
1156
1157 // Correction happens over a number of seconds.
1158 Vector3 unscaledContrib = ret;
1159 ret /= m_verticalAttractionTimescale;
1160
1161 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}",
1162 Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret);
1010 } 1163 }
1164 return ret;
1165 }
1166
1167 // Return the angular correction to correct the direction the vehicle is pointing to be
1168 // the direction is should want to be pointing.
1169 // The vehicle is moving in some direction and correct its orientation to it is pointing
1170 // in that direction.
1171 // TODO: implement reference frame.
1172 public Vector3 ComputeAngularDeflection()
1173 {
1174 Vector3 ret = Vector3.Zero;
1175 return ret; // DEBUG DEBUG DEBUG debug one force at a time
1011 1176
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1177 if (m_angularDeflectionEfficiency != 0)
1013 { 1178 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1179 // The direction the vehicle is moving
1015 Prim.ZeroAngularMotion(true); 1180 Vector3 movingDirection = VehicleVelocity;
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1181 movingDirection.Normalize();
1182
1183 // The direction the vehicle is pointing
1184 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1185 pointingDirection.Normalize();
1186
1187 // The difference between what is and what should be
1188 Vector3 deflectionError = movingDirection - pointingDirection;
1189
1190 // Scale the correction by recovery timescale and efficiency
1191 ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency;
1192 ret /= m_angularDeflectionTimescale;
1193
1194 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1195 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1017 } 1196 }
1018 else 1197 return ret;
1198 }
1199
1200 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1201 // is tipped around the X axis.
1202 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1203 // The vertical attractor feature must be enabled in order for the banking behavior to
1204 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1205 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1206 // of the yaw effect will be proportional to the
1207 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1208 // velocity along its preferred axis of motion.
1209 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1210 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1211 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1212 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1213 // Negating the banking coefficient will make it so that the vehicle leans to the
1214 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1215 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1216 // banking vehicles do what you want rather than what the laws of physics allow.
1217 // For example, consider a real motorcycle...it must be moving forward in order for
1218 // it to turn while banking, however video-game motorcycles are often configured
1219 // to turn in place when at a dead stop--because they are often easier to control
1220 // that way using the limited interface of the keyboard or game controller. The
1221 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1222 // banking by functioning as a slider between a banking that is correspondingly
1223 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1224 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1225 // to "dynamic" where the banking is also proportional to its velocity along its
1226 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1227 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1228 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1229 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1230 // make a sluggish vehicle by giving it a timescale of several seconds.
1231 public Vector3 ComputeAngularBanking()
1232 {
1233 Vector3 ret = Vector3.Zero;
1234
1235 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1236 {
1020 // Apply to the body. 1237 // This works by rotating a unit vector to the orientation of the vehicle. The
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1238 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1239 // up to one for full over).
1023 // velocity needs to be scaled by the timestep. 1240 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1241
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1242 // Figure out the yaw value for this much roll.
1026 1243 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1027 // Decay the angular movement for next time 1244 // Keep the sign
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1245 if (rollComponents.Y < 0f)
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1246 turnComponent = -turnComponent;
1030 1247
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1248 // TODO: there must be a better computation of the banking force.
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1249 float bankingTurnForce = turnComponent;
1250
1251 // actual error = static turn error + dynamic turn error
1252 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1253 // TODO: the banking effect should not go to infinity but what to limit it to?
1254 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1255
1256 // Build the force vector to change rotation from what it is to what it should be
1257 ret.Z = -mixedBankingError;
1258
1259 // Don't do it all at once.
1260 ret /= m_bankingTimescale;
1261
1262 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1263 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1033 } 1264 }
1034 } //end MoveAngular 1265 return ret;
1266 }
1035 1267
1268 // This is from previous instantiations of XXXDynamics.cs.
1269 // Applies roll reference frame.
1270 // TODO: is this the right way to separate the code to do this operation?
1271 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1272 internal void LimitRotation(float timestep)
1037 { 1273 {
1038 Quaternion rotq = Prim.ForceOrientation; 1274 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1275 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1276 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1277 {
@@ -1063,12 +1299,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1299 }
1064 if (rotq != m_rot) 1300 if (rotq != m_rot)
1065 { 1301 {
1066 Prim.ForceOrientation = m_rot; 1302 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1303 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1304 }
1069 1305
1070 } 1306 }
1071 1307
1308 private float ClampInRange(float low, float val, float high)
1309 {
1310 return Math.Max(low, Math.Min(val, high));
1311 }
1312
1072 // Invoke the detailed logger and output something if it's enabled. 1313 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1314 private void VDetailLog(string msg, params Object[] args)
1074 { 1315 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..2017fa5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
35public abstract class BSLinkset 44public abstract class BSLinkset
36{ 45{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 46 // private static string LogHeader = "[BULLETSIM LINKSET]";
@@ -87,13 +96,6 @@ public abstract class BSLinkset
87 return BSPhysicsShapeType.SHAPE_UNKNOWN; 96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 97 }
89 98
90 // Linksets move around the children so the linkset might need to compute the child position
91 public virtual OMV.Vector3 Position(BSPhysObject member)
92 { return member.RawPosition; }
93 public virtual OMV.Quaternion Orientation(BSPhysObject member)
94 { return member.RawOrientation; }
95 // TODO: does this need to be done for Velocity and RotationalVelocityy?
96
97 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
98 protected float m_mass; 100 protected float m_mass;
99 public float LinksetMass 101 public float LinksetMass
@@ -116,7 +118,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 118 get { return ComputeLinksetGeometricCenter(); }
117 } 119 }
118 120
119 protected void Initialize(BSScene scene, BSPhysObject parent) 121 protected BSLinkset(BSScene scene, BSPhysObject parent)
120 { 122 {
121 // A simple linkset of one (no children) 123 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 124 LinksetID = m_nextLinksetID++;
@@ -127,6 +129,7 @@ public abstract class BSLinkset
127 LinksetRoot = parent; 129 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 130 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass; 131 m_mass = parent.RawMass;
132 Rebuilding = false;
130 } 133 }
131 134
132 // Link to a linkset where the child knows the parent. 135 // Link to a linkset where the child knows the parent.
@@ -219,7 +222,7 @@ public abstract class BSLinkset
219 // I am the root of a linkset and a new child is being added 222 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 223 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 224 protected abstract void AddChildToLinkset(BSPhysObject child);
222 225
223 // I am the root of a linkset and one of my children is being removed. 226 // I am the root of a linkset and one of my children is being removed.
224 // Safe to call even if the child is not really in my linkset. 227 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 228 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@@ -229,6 +232,10 @@ public abstract class BSLinkset
229 // May be called at runtime or taint-time. 232 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 233 public abstract void Refresh(BSPhysObject requestor);
231 234
235 // Flag denoting the linkset is in the process of being rebuilt.
236 // Used to know not the schedule a rebuild in the middle of a rebuild.
237 protected bool Rebuilding { get; set; }
238
232 // The object is going dynamic (physical). Do any setup necessary 239 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 240 // for a dynamic linkset.
234 // Only the state of the passed object can be modified. The rest of the linkset 241 // Only the state of the passed object can be modified. The rest of the linkset
@@ -245,8 +252,9 @@ public abstract class BSLinkset
245 252
246 // Called when a parameter update comes from the physics engine for any object 253 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 254 // of the linkset is received.
255 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 256 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 257 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
250 258
251 // Routine used when rebuilding the body of the root of the linkset 259 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 260 // Destroy all the constraints have have been made to root.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..2a7b72c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,54 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30 30
31using OpenSim.Framework;
32
31using OMV = OpenMetaverse; 33using OMV = OpenMetaverse;
32 34
33namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
34{ 36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public OMV.Vector3 OffsetPos;
44 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
46 {
47 OffsetPos = p;
48 OffsetRot = r;
49 }
50 public override void Clear()
51 {
52 OffsetPos = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity;
54 }
55 public override string ToString()
56 {
57 StringBuilder buff = new StringBuilder();
58 buff.Append("<p=");
59 buff.Append(OffsetPos.ToString());
60 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString());
62 buff.Append(">");
63 return buff.ToString();
64 }
65};
66
35public sealed class BSLinksetCompound : BSLinkset 67public sealed class BSLinksetCompound : BSLinkset
36{ 68{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 70
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 72 {
41 base.Initialize(scene, parent);
42 } 73 }
43 74
44 // For compound implimented linksets, if there are children, use compound shape for the root. 75 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 77 {
78 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 80 if (IsRoot(requestor) && HasAnyChildren)
49 { 81 {
@@ -55,23 +87,27 @@ public sealed class BSLinksetCompound : BSLinkset
55 87
56 // When physical properties are changed the linkset needs to recalculate 88 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 89 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 90 public override void Refresh(BSPhysObject requestor)
61 { 91 {
62 // External request for Refresh (from BSPrim) is not necessary 92 // Something changed so do the rebuilding thing
63 // InternalRefresh(requestor); 93 // ScheduleRebuild();
64 } 94 }
65 95
66 private void InternalRefresh(BSPhysObject requestor) 96 // Schedule a refresh to happen after all the other taint processing.
97 private void ScheduleRebuild(BSPhysObject requestor)
67 { 98 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 99 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,rebuilding={1}",
69 // Queue to happen after all the other taint processing 100 requestor.LocalID, Rebuilding);
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 101 // When rebuilding, it is possible to set properties that would normally require a rebuild.
102 // If already rebuilding, don't request another rebuild.
103 if (!Rebuilding)
71 { 104 {
72 if (IsRoot(requestor) && HasAnyChildren) 105 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 106 {
74 }); 107 if (HasAnyChildren)
108 RecomputeLinksetCompound();
109 });
110 }
75 } 111 }
76 112
77 // The object is going dynamic (physical). Do any setup necessary 113 // The object is going dynamic (physical). Do any setup necessary
@@ -84,12 +120,23 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 120 {
85 bool ret = false; 121 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 122 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 123 if (IsRoot(child))
124 {
125 // The root is going dynamic. Make sure mass is properly set.
126 m_mass = ComputeLinksetMass();
127 ScheduleRebuild(LinksetRoot);
128 }
129 else
88 { 130 {
89 // Physical children are removed from the world as the shape ofthe root compound 131 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 132 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 133 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 134 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
135 // We don't want collisions from the old linkset children.
136 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
137
138 child.PhysBody.collisionType = CollisionType.LinksetChild;
139
93 ret = true; 140 ret = true;
94 } 141 }
95 return ret; 142 return ret;
@@ -104,33 +151,39 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 151 {
105 bool ret = false; 152 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 153 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 154 if (IsRoot(child))
155 {
156 ScheduleRebuild(LinksetRoot);
157 }
158 else
108 { 159 {
109 // The non-physical children can come back to life. 160 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 161 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 162
163 child.PhysBody.collisionType = CollisionType.LinksetChild;
164
165 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 166 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true; 167 ret = true;
114 } 168 }
115 return ret; 169 return ret;
116 } 170 }
117 171
118 // Called at taint-time!! 172 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
119 public override void UpdateProperties(BSPhysObject updated)
120 { 173 {
121 // Nothing to do for constraints on property updates 174 // The user moving a child around requires the rebuilding of the linkset compound shape
122 } 175 // One problem is this happens when a border is crossed -- the simulator implementation
123 176 // is to store the position into the group which causes the move of the object
124 // The children move around in relationship to the root. 177 // but it also means all the child positions get updated.
125 // Just grab the current values of wherever it is right now. 178 // What would cause an unnecessary rebuild so we make sure the linkset is in a
126 public override OMV.Vector3 Position(BSPhysObject member) 179 // region before bothering to do a rebuild.
127 { 180 if (!IsRoot(updated)
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr); 181 && !physicalUpdate
129 } 182 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
130 183 {
131 public override OMV.Quaternion Orientation(BSPhysObject member) 184 updated.LinksetInfo = null;
132 { 185 ScheduleRebuild(updated);
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 186 }
134 } 187 }
135 188
136 // Routine called when rebuilding the body of some member of the linkset. 189 // Routine called when rebuilding the body of some member of the linkset.
@@ -146,20 +199,58 @@ public sealed class BSLinksetCompound : BSLinkset
146 199
147 if (!IsRoot(child)) 200 if (!IsRoot(child))
148 { 201 {
149 // Cause the current shape to be freed and the new one to be built. 202 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 203 // its position in the linkset.
151 ret = true; 204 RecomputeChildWorldPosition(child, true);
152 } 205 }
153 206
207 // Cannot schedule a refresh/rebuild here because this routine is called when
208 // the linkset is being rebuilt.
209 // InternalRefresh(LinksetRoot);
210
154 return ret; 211 return ret;
155 } 212 }
156 213
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 214 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 215 // this routine will restore the removed constraints.
159 // Called at taint-time!! 216 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 217 public override void RestoreBodyDependencies(BSPrim child)
161 { 218 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 219 }
220
221 // When the linkset is built, the child shape is added to the compound shape relative to the
222 // root shape. The linkset then moves around but this does not move the actual child
223 // prim. The child prim's location must be recomputed based on the location of the root shape.
224 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
225 {
226 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
227 if (lci != null)
228 {
229 if (inTaintTime)
230 {
231 OMV.Vector3 oldPos = child.RawPosition;
232 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
233 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
234 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
235 child.LocalID, oldPos, lci, child.RawPosition);
236 }
237 else
238 {
239 // TaintedObject is not used here so the raw position is set now and not at taint-time.
240 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
241 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
242 }
243 }
244 else
245 {
246 // This happens when children have been added to the linkset but the linkset
247 // has not been constructed yet. So like, at taint time, adding children to a linkset
248 // and then changing properties of the children (makePhysical, for instance)
249 // but the post-print action of actually rebuilding the linkset has not yet happened.
250 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
251 // LogHeader, child.LocalID);
252 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
253 }
163 } 254 }
164 255
165 // ================================================================ 256 // ================================================================
@@ -174,14 +265,14 @@ public sealed class BSLinksetCompound : BSLinkset
174 265
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 266 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 267
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 268 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 269 ScheduleRebuild(child);
179 } 270 }
180 return; 271 return;
181 } 272 }
182 273
183 // Remove the specified child from the linkset. 274 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 275 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 276 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 277 {
187 if (m_children.Remove(child)) 278 if (m_children.Remove(child))
@@ -192,6 +283,7 @@ public sealed class BSLinksetCompound : BSLinkset
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 283 child.LocalID, child.PhysBody.ptr.ToString("X"));
193 284
194 // Cause the child's body to be rebuilt and thus restored to normal operation 285 // Cause the child's body to be rebuilt and thus restored to normal operation
286 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 287 child.ForceBodyShapeRebuild(false);
196 288
197 if (!HasAnyChildren) 289 if (!HasAnyChildren)
@@ -201,8 +293,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 293 }
202 else 294 else
203 { 295 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 296 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 297 ScheduleRebuild(child);
206 } 298 }
207 } 299 }
208 return; 300 return;
@@ -215,54 +307,83 @@ public sealed class BSLinksetCompound : BSLinkset
215 // Called at taint time!! 307 // Called at taint time!!
216 private void RecomputeLinksetCompound() 308 private void RecomputeLinksetCompound()
217 { 309 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 310 try
219 LinksetRoot.ForceBodyShapeRebuild(true); 311 {
312 // Suppress rebuilding while rebuilding
313 Rebuilding = true;
220 314
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 315 // Cause the root shape to be rebuilt as a compound object with just the root in it
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 316 LinksetRoot.ForceBodyShapeRebuild(true);
223 317
224 // Add a shape for each of the other children in the linkset 318 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
225 ForEachMember(delegate(BSPhysObject cPrim) 319 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
226 { 320
227 if (!IsRoot(cPrim)) 321 // Add a shape for each of the other children in the linkset
322 ForEachMember(delegate(BSPhysObject cPrim)
228 { 323 {
229 // Each child position and rotation is given relative to the root. 324 if (!IsRoot(cPrim))
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 325 {
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; 326 // Compute the displacement of the child from the root of the linkset.
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; 327 // This info is saved in the child prim so the relationship does not
328 // change over time and the new child position can be computed
329 // when the linkset is being disassembled (the linkset may have moved).
330 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
331 if (lci == null)
332 {
333 // Each child position and rotation is given relative to the root.
334 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
335 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
336 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
337
338 // Save relative position for recomputing child's world position after moving linkset.
339 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
340 cPrim.LinksetInfo = lci;
341 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
342 }
233 343
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 344 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 345 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
236 346
237 if (cPrim.PhysShape.isNativeShape) 347 if (cPrim.PhysShape.isNativeShape)
238 { 348 {
239 // Native shapes are not shared so we need to create a new one. 349 // A native shape is turning into a hull collision shape because native
240 // A mesh or hull is created because scale is not available on a native shape. 350 // shapes are not shared so we have to hullify it so it will be tracked
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 351 // and freed at the correct time. This also solves the scaling problem
242 BulletShape saveShape = cPrim.PhysShape; 352 // (native shapes scaled but hull/meshes are assumed to not be).
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 353 // TODO: decide of the native shape can just be used in the compound shape.
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); 354 // Use call to CreateGeomNonSpecial().
245 BulletShape newShape = cPrim.PhysShape; 355 BulletShape saveShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape; 356 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); 357 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
248 } 358 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
249 else 359 BulletShape newShape = cPrim.PhysShape;
250 { 360 cPrim.PhysShape = saveShape;
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 361 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 362 }
363 else
253 { 364 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 365 // For the shared shapes (meshes and hulls), just use the shape in the child.
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 366 // The reference count added here will be decremented when the compound shape
367 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
368 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
369 {
370 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
371 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
372 }
373 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
256 } 374 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 } 375 }
259 } 376 return false; // 'false' says to move onto the next child in the list
260 return false; // 'false' says to move onto the next child in the list 377 });
261 });
262 378
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 379 // With all of the linkset packed into the root prim, it has the mass of everyone.
264 float linksetMass = LinksetMass; 380 float linksetMass = LinksetMass;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 381 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
382 }
383 finally
384 {
385 Rebuilding = false;
386 }
266 387
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 388 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
268 389
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..8c36c31 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) 39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 40 {
41 base.Initialize(scene, parent);
42 } 41 }
43 42
44 // When physical properties are changed the linkset needs to recalculate 43 // When physical properties are changed the linkset needs to recalculate
@@ -79,23 +78,11 @@ public sealed class BSLinksetConstraints : BSLinkset
79 } 78 }
80 79
81 // Called at taint-time!! 80 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated) 81 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
83 { 82 {
84 // Nothing to do for constraints on property updates 83 // Nothing to do for constraints on property updates
85 } 84 }
86 85
87 // The children of the linkset are moved around by the constraints.
88 // Just grab the current values of wherever it is right now.
89 public override OMV.Vector3 Position(BSPhysObject member)
90 {
91 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
92 }
93
94 public override OMV.Quaternion Orientation(BSPhysObject member)
95 {
96 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
97 }
98
99 // Routine called when rebuilding the body of some member of the linkset. 86 // Routine called when rebuilding the body of some member of the linkset.
100 // Destroy all the constraints have have been made to root and set 87 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step. 88 // up to rebuild the constraints before the next simulation step.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..c113a43
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,200 @@
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 System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",60f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 MaterialAttributes thisAttrib = Attributes[matType];
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null)
186 {
187 fieldInfo.SetValue(thisAttrib, val);
188 Attributes[matType] = thisAttrib;
189 }
190 }
191
192 // Given a material type, return a structure of attributes.
193 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
194 {
195 int ind = (int)type;
196 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
197 return Attributes[ind];
198 }
199}
200}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..e0faf4e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,220 @@
1using System; 1/*
2using System.Collections.Generic; 2 * Copyright (c) Contributors, http://opensimulator.org/
3using System.Text; 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4using OpenMetaverse; 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6namespace OpenSim.Region.Physics.BulletSPlugin 6 * modification, are permitted provided that the following conditions are met:
7{ 7 * * Redistributions of source code must retain the above copyright
8public abstract class BSMotor 8 * notice, this list of conditions and the following disclaimer.
9{ 9 * * Redistributions in binary form must reproduce the above copyright
10 public virtual void Reset() { } 10 * notice, this list of conditions and the following disclaimer in the
11 public virtual void Zero() { } 11 * documentation and/or other materials provided with the distribution.
12} 12 * * Neither the name of the OpenSimulator Project nor the
13// Can all the incremental stepping be replaced with motor classes? 13 * names of its contributors may be used to endorse or promote products
14public class BSVMotor : BSMotor 14 * derived from this software without specific prior written permission.
15{ 15 *
16 public Vector3 FrameOfReference { get; set; } 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 public Vector3 Offset { get; set; } 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 public float TimeScale { get; set; } 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 public float TargetValueDecayTimeScale { get; set; } 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 public Vector3 CurrentValueReductionTimescale { get; set; } 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 public float Efficiency { get; set; } 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 public Vector3 TargetValue { get; private set; } 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 public Vector3 CurrentValue { get; private set; } 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 26 *
27 27 */
28 28using System;
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 29using System.Collections.Generic;
30 { 30using System.Text;
31 TimeScale = timeScale; 31using OpenMetaverse;
32 TargetValueDecayTimeScale = decayTimeScale; 32
33 CurrentValueReductionTimescale = frictionTimeScale; 33namespace OpenSim.Region.Physics.BulletSPlugin
34 Efficiency = efficiency; 34{
35 } 35public abstract class BSMotor
36 public void SetCurrent(Vector3 current) 36{
37 { 37 // Timescales and other things can be turned off by setting them to 'infinite'.
38 CurrentValue = current; 38 public const float Infinite = 12345f;
39 } 39 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
40 public void SetTarget(Vector3 target) 40
41 { 41 public BSMotor(string useName)
42 TargetValue = target; 42 {
43 } 43 UseName = useName;
44 public Vector3 Step(float timeStep) 44 PhysicsScene = null;
45 { 45 }
46 if (CurrentValue.LengthSquared() > 0.001f) 46 public virtual void Reset() { }
47 { 47 public virtual void Zero() { }
48 // Vector3 origDir = Target; // DEBUG 48
49 // Vector3 origVel = CurrentValue; // DEBUG 49 // A name passed at motor creation for easily identifyable debugging messages.
50 50 public string UseName { get; private set; }
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete 51
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; 52 // Used only for outputting debug information. Might not be set so check for null.
53 CurrentValue += addAmount; 53 public BSScene PhysicsScene { get; set; }
54 54 protected void MDetailLog(string msg, params Object[] parms)
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 55 {
56 TargetValue *= (1f - decayFactor); 56 if (PhysicsScene != null)
57 57 {
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; 58 if (PhysicsScene.VehicleLoggingEnabled)
59 CurrentValue *= (Vector3.One - frictionFactor); 59 {
60 } 60 PhysicsScene.DetailLog(msg, parms);
61 else 61 }
62 { 62 }
63 // if what remains of direction is very small, zero it. 63 }
64 TargetValue = Vector3.Zero; 64}
65 CurrentValue = Vector3.Zero; 65// Can all the incremental stepping be replaced with motor classes?
66 66
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68 } 68// The TargetValue decays in TargetValueDecayTimeScale and
69 return CurrentValue; 69// the CurrentValue will be held back by FrictionTimeScale.
70 } 70// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.
71} 71
72 72// For instance, if something is moving at speed X and the desired speed is Y,
73public class BSFMotor : BSMotor 73// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
74{ 74// values of CurrentValue are returned that approach the TargetValue.
75 public float TimeScale { get; set; } 75// The feature of decaying TargetValue is so vehicles will eventually
76 public float DecayTimeScale { get; set; } 76// come to a stop rather than run forever. This can be disabled by
77 public float Friction { get; set; } 77// setting TargetValueDecayTimescale to 'infinite'.
78 public float Efficiency { get; set; } 78// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
79 79public class BSVMotor : BSMotor
80 public float Target { get; private set; } 80{
81 public float CurrentValue { get; private set; } 81 // public Vector3 FrameOfReference { get; set; }
82 82 // public Vector3 Offset { get; set; }
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) 83
84 { 84 public float TimeScale { get; set; }
85 } 85 public float TargetValueDecayTimeScale { get; set; }
86 public void SetCurrent(float target) 86 public Vector3 FrictionTimescale { get; set; }
87 { 87 public float Efficiency { get; set; }
88 } 88
89 public void SetTarget(float target) 89 public Vector3 TargetValue { get; private set; }
90 { 90 public Vector3 CurrentValue { get; private set; }
91 } 91
92 public float Step(float timeStep) 92 public BSVMotor(string useName)
93 { 93 : base(useName)
94 return 0f; 94 {
95 } 95 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
96} 96 Efficiency = 1f;
97public class BSPIDMotor : BSMotor 97 FrictionTimescale = BSMotor.InfiniteVector;
98{ 98 CurrentValue = TargetValue = Vector3.Zero;
99 // TODO: write and use this one 99 }
100 BSPIDMotor() 100 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
101 { 101 : this(useName)
102 } 102 {
103} 103 TimeScale = timeScale;
104} 104 TargetValueDecayTimeScale = decayTimeScale;
105 FrictionTimescale = frictionTimeScale;
106 Efficiency = efficiency;
107 CurrentValue = TargetValue = Vector3.Zero;
108 }
109 public void SetCurrent(Vector3 current)
110 {
111 CurrentValue = current;
112 }
113 public void SetTarget(Vector3 target)
114 {
115 TargetValue = target;
116 }
117
118 // A form of stepping that does not take the time quantum into account.
119 // The caller must do the right thing later.
120 public Vector3 Step()
121 {
122 return Step(1f);
123 }
124
125 public Vector3 Step(float timeStep)
126 {
127 Vector3 returnCurrent = Vector3.Zero;
128 if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
129 {
130 Vector3 origTarget = TargetValue; // DEBUG
131 Vector3 origCurrVal = CurrentValue; // DEBUG
132
133 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
134 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
135 CurrentValue += addAmount;
136
137 // The desired value reduces to zero which also reduces the difference with current.
138 // If the decay time is infinite, don't decay at all.
139 float decayFactor = 0f;
140 if (TargetValueDecayTimeScale != BSMotor.Infinite)
141 {
142 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
143 TargetValue *= (1f - decayFactor);
144 }
145
146 Vector3 frictionFactor = Vector3.Zero;
147 if (FrictionTimescale != BSMotor.InfiniteVector)
148 {
149 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
150 // Individual friction components can be 'infinite' so compute each separately.
151 frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
152 frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
153 frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
154 CurrentValue *= (Vector3.One - frictionFactor);
155 }
156
157 returnCurrent = CurrentValue;
158
159 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
160 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
161 timeStep, TimeScale, addAmount,
162 TargetValueDecayTimeScale, decayFactor,
163 FrictionTimescale, frictionFactor);
164 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
165 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
166 addAmount, decayFactor, frictionFactor, returnCurrent);
167 }
168 else
169 {
170 // Difference between what we have and target is small. Motor is done.
171 CurrentValue = Vector3.Zero;
172 TargetValue = Vector3.Zero;
173
174 MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
175 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
176
177 }
178 return returnCurrent;
179 }
180 public override string ToString()
181 {
182 return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
183 UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
184 }
185}
186
187public class BSFMotor : BSMotor
188{
189 public float TimeScale { get; set; }
190 public float DecayTimeScale { get; set; }
191 public float Friction { get; set; }
192 public float Efficiency { get; set; }
193
194 public float Target { get; private set; }
195 public float CurrentValue { get; private set; }
196
197 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
198 : base(useName)
199 {
200 }
201 public void SetCurrent(float target)
202 {
203 }
204 public void SetTarget(float target)
205 {
206 }
207 public float Step(float timeStep)
208 {
209 return 0f;
210 }
211}
212public class BSPIDMotor : BSMotor
213{
214 // TODO: write and use this one
215 public BSPIDMotor(string useName)
216 : base(useName)
217 {
218 }
219}
220}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..92a5f2f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -60,6 +60,9 @@ public abstract class BSPhysObject : PhysicsActor
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 60 Linkset = BSLinkset.Factory(PhysicsScene, this);
61 LastAssetBuildFailed = false; 61 LastAssetBuildFailed = false;
62 62
63 // Default material type
64 Material = MaterialAttributes.Material.Wood;
65
63 CollisionCollection = new CollisionEventUpdate(); 66 CollisionCollection = new CollisionEventUpdate();
64 SubscribedEventsMs = 0; 67 SubscribedEventsMs = 0;
65 CollidingStep = 0; 68 CollidingStep = 0;
@@ -72,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor
72 public string TypeName { get; protected set; } 75 public string TypeName { get; protected set; }
73 76
74 public BSLinkset Linkset { get; set; } 77 public BSLinkset Linkset { get; set; }
78 public BSLinksetInfo LinksetInfo { get; set; }
75 79
76 // Return the object mass without calculating it or having side effects 80 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 81 public abstract float RawMass { get; }
@@ -105,10 +109,17 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 109 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 110 public EntityProperties LastEntityProperties { get; set; }
107 111
108 public abstract OMV.Vector3 Scale { get; set; } 112 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 113 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 114 public abstract bool IsStatic { get; }
111 115
116 // Materialness
117 public MaterialAttributes.Material Material { get; private set; }
118 public override void SetMaterial(int material)
119 {
120 Material = (MaterialAttributes.Material)material;
121 }
122
112 // Stop all physical motion. 123 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 124 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 125 public abstract void ZeroAngularMotion(bool inTaintTime);
@@ -128,6 +139,17 @@ public abstract class BSPhysObject : PhysicsActor
128 public abstract OMV.Quaternion RawOrientation { get; set; } 139 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 140 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 141
142 // The system is telling us the velocity it wants to move at.
143 protected OMV.Vector3 m_targetVelocity;
144 public override OMV.Vector3 TargetVelocity
145 {
146 get { return m_targetVelocity; }
147 set
148 {
149 m_targetVelocity = value;
150 Velocity = value;
151 }
152 }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 153 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 154
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 155 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -192,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor
192 { 214 {
193 bool ret = true; 215 bool ret = true;
194 // If the 'no collision' call, force it to happen right now so quick collision_end 216 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 217 bool force = (CollisionCollection.Count == 0);
196 218
197 // throttle the collisions to the number of milliseconds specified in the subscription 219 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 220 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -210,8 +232,10 @@ public abstract class BSPhysObject : PhysicsActor
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 232 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 233 base.SendCollisionUpdate(CollisionCollection);
212 234
213 // The collisionCollection structure is passed around in the simulator. 235 // The CollisionCollection instance is passed around in the simulator.
214 // Make sure we don't have a handle to that one and that a new one is used for next time. 236 // Make sure we don't have a handle to that one and that a new one is used for next time.
237 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
238 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 239 CollisionCollection = new CollisionEventUpdate();
216 } 240 }
217 return ret; 241 return ret;
@@ -229,7 +253,8 @@ public abstract class BSPhysObject : PhysicsActor
229 253
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 254 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 255 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 256 if (PhysBody.HasPhysicalBody)
257 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 258 });
234 } 259 }
235 else 260 else
@@ -243,7 +268,9 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 268 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 269 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 270 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 271 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
272 if (PhysBody.HasPhysicalBody)
273 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 274 });
248 } 275 }
249 // Return 'true' if the simulator wants collision events 276 // Return 'true' if the simulator wants collision events
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..758d92b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 49
51 private bool _grabbed; 50 private bool _grabbed;
@@ -93,7 +92,7 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 92 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 93 _position = pos;
95 _size = size; 94 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 96 _orientation = rotation;
98 _buoyancy = 1f; 97 _buoyancy = 1f;
99 _velocity = OMV.Vector3.Zero; 98 _velocity = OMV.Vector3.Zero;
@@ -108,8 +107,8 @@ public sealed class BSPrim : BSPhysObject
108 _mass = CalculateMass(); 107 _mass = CalculateMass();
109 108
110 // No body or shape yet 109 // No body or shape yet
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 110 PhysBody = new BulletBody(LocalID);
112 PhysShape = new BulletShape(IntPtr.Zero); 111 PhysShape = new BulletShape();
113 112
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 113 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 114 // do the actual object creation at taint time
@@ -143,7 +142,9 @@ public sealed class BSPrim : BSPhysObject
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 142 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 143 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 144 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
145 PhysBody.Clear();
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
147 PhysShape.Clear();
147 }); 148 });
148 } 149 }
149 150
@@ -157,12 +158,10 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 158 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built. 159 // the physical shape, that is done when the geometry is built.
159 _size = value; 160 _size = value;
161 Scale = _size;
160 ForceBodyShapeRebuild(false); 162 ForceBodyShapeRebuild(false);
161 } 163 }
162 } 164 }
163 // Scale is what we set in the physics engine. It is different than 'size' in that
164 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
165 public override OMV.Vector3 Scale { get; set; }
166 165
167 public override PrimitiveBaseShape Shape { 166 public override PrimitiveBaseShape Shape {
168 set { 167 set {
@@ -189,13 +188,17 @@ public sealed class BSPrim : BSPhysObject
189 } 188 }
190 } 189 }
191 public override bool Selected { 190 public override bool Selected {
192 set { 191 set
193 _isSelected = value; 192 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 193 if (value != _isSelected)
195 { 194 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 195 _isSelected = value;
197 SetObjectDynamic(false); 196 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 197 {
198 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
199 SetObjectDynamic(false);
200 });
201 }
199 } 202 }
200 } 203 }
201 public override void CrossingFailure() { return; } 204 public override void CrossingFailure() { return; }
@@ -244,7 +247,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 247 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 248 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 249 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 250 if (PhysBody.HasPhysicalBody)
251 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
248 }); 252 });
249 } 253 }
250 public override void ZeroAngularMotion(bool inTaintTime) 254 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,8 +257,12 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 257 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 258 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 259 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 260 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 261 if (PhysBody.HasPhysicalBody)
262 {
263 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
264 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
265 }
258 }); 266 });
259 } 267 }
260 268
@@ -271,9 +279,12 @@ public sealed class BSPrim : BSPhysObject
271 } 279 }
272 public override OMV.Vector3 Position { 280 public override OMV.Vector3 Position {
273 get { 281 get {
282 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
283 * and does not fetch this position info for children. Thus this is commented out.
274 // child prims move around based on their parent. Need to get the latest location 284 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this)) 285 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this); 286 _position = Linkset.PositionGet(this);
287 */
277 288
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 289 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 290 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
@@ -281,18 +292,22 @@ public sealed class BSPrim : BSPhysObject
281 } 292 }
282 set { 293 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 294 // If the position must be forced into the physics engine, use ForcePosition.
295 // All positions are given in world positions.
284 if (_position == value) 296 if (_position == value)
285 { 297 {
298 DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 299 return;
287 } 300 }
288 _position = value; 301 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 302 PositionSanityCheck(false);
303
304 // A linkset might need to know if a component information changed.
305 Linkset.UpdateProperties(this, false);
306
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 307 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 308 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 309 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 310 ForcePosition = _position;
295 ActivateIfPhysical(false);
296 }); 311 });
297 } 312 }
298 } 313 }
@@ -303,9 +318,11 @@ public sealed class BSPrim : BSPhysObject
303 } 318 }
304 set { 319 set {
305 _position = value; 320 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 321 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 322 {
308 ActivateIfPhysical(false); 323 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
324 ActivateIfPhysical(false);
325 }
309 } 326 }
310 } 327 }
311 328
@@ -316,39 +333,46 @@ public sealed class BSPrim : BSPhysObject
316 { 333 {
317 bool ret = false; 334 bool ret = false;
318 335
336 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
337 {
338 // The physical object is out of the known/simulated area.
339 // Upper levels of code will handle the transition to other areas so, for
340 // the time, we just ignore the position.
341 return ret;
342 }
343
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 344 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 345 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 346 if (RawPosition.Z < terrainHeight)
322 { 347 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 348 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 349 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 350 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 351 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
327 ret = true; 352 ret = true;
328 } 353 }
329 354
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 355 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 356 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 357 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 358 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 359 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 360 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 361 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 362 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
338 ret = true; 363 ret = true;
339 } 364 }
340 } 365 }
341 366
342 // TODO: check for out of bounds
343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 367 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
368 // TODO: This should be intergrated with a geneal physics action mechanism.
369 // TODO: This should be moderated with PID'ness.
345 if (ret) 370 if (ret)
346 { 371 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 372 // Apply upforce and overcome gravity.
348 { 373 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
349 // Apply upforce and overcome gravity. 374 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; 375 AddForce(correctionForce, false, inTaintTime);
351 });
352 } 376 }
353 return ret; 377 return ret;
354 } 378 }
@@ -408,7 +432,8 @@ public sealed class BSPrim : BSPhysObject
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 432 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
409 { 433 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 434 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 435 if (PhysBody.HasPhysicalBody)
436 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
412 }); 437 });
413 } 438 }
414 } 439 }
@@ -502,7 +527,8 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 527 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 528 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 529 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 530 if (PhysBody.HasPhysicalBody)
531 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
506 }); 532 });
507 } 533 }
508 } 534 }
@@ -537,23 +563,32 @@ public sealed class BSPrim : BSPhysObject
537 } 563 }
538 public override OMV.Quaternion Orientation { 564 public override OMV.Quaternion Orientation {
539 get { 565 get {
566 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
567 * and does not fetch this position info for children. Thus this is commented out.
540 // Children move around because tied to parent. Get a fresh value. 568 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this)) 569 if (!Linkset.IsRoot(this))
542 { 570 {
543 _orientation = Linkset.Orientation(this); 571 _orientation = Linkset.OrientationGet(this);
544 } 572 }
573 */
545 return _orientation; 574 return _orientation;
546 } 575 }
547 set { 576 set {
548 if (_orientation == value) 577 if (_orientation == value)
549 return; 578 return;
550 _orientation = value; 579 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 580
581 // A linkset might need to know if a component information changed.
582 Linkset.UpdateProperties(this, false);
583
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 584 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 585 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 586 if (PhysBody.HasPhysicalBody)
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 587 {
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 588 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
589 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
590 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
591 }
557 }); 592 });
558 } 593 }
559 } 594 }
@@ -644,10 +679,7 @@ public sealed class BSPrim : BSPhysObject
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 679 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
645 680
646 // Collision filter can be set only when the object is in the world 681 // Collision filter can be set only when the object is in the world
647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) 682 PhysBody.ApplyCollisionMask();
648 {
649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
650 }
651 683
652 // Recompute any linkset parameters. 684 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that 685 // When going from non-physical to physical, this re-enables the constraints that
@@ -672,8 +704,12 @@ public sealed class BSPrim : BSPhysObject
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 704 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 705 // Stop all movement
674 ZeroMotion(true); 706 ZeroMotion(true);
675 // Center of mass is at the center of the object 707
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 708 // Set various physical properties so other object interact properly
709 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
710 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
711 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
712
677 // Mass is zero which disables a bunch of physics stuff in Bullet 713 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 714 UpdatePhysicalMassProperties(0f);
679 // Set collision detection parameters 715 // Set collision detection parameters
@@ -682,24 +718,27 @@ public sealed class BSPrim : BSPhysObject
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 718 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 719 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
684 } 720 }
685 // There can be special things needed for implementing linksets 721
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 722 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 723 // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 724 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 725 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
726
727 // This collides like a static object
728 PhysBody.collisionType = CollisionType.Static;
691 729
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 730 // There can be special things needed for implementing linksets
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 731 Linkset.MakeStatic(this);
694 } 732 }
695 else 733 else
696 { 734 {
697 // Not a Bullet static object 735 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 736 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
699 737
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 738 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 739 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 740 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
741 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
703 742
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 743 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
705 // Since this can be called multiple times, only zero forces when becoming physical 744 // Since this can be called multiple times, only zero forces when becoming physical
@@ -727,16 +766,15 @@ public sealed class BSPrim : BSPhysObject
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 766 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 767 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
729 768
730 // There might be special things needed for implementing linksets. 769 // This collides like an object.
731 Linkset.MakeDynamic(this); 770 PhysBody.collisionType = CollisionType.Dynamic;
732 771
733 // Force activation of the object so Bullet will act on it. 772 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 773 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 774 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737 775
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 776 // There might be special things needed for implementing linksets.
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 777 Linkset.MakeDynamic(this);
740 } 778 }
741 } 779 }
742 780
@@ -763,8 +801,9 @@ public sealed class BSPrim : BSPhysObject
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 801 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 802 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 803 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 804
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 805 // Change collision info from a static object to a ghosty collision object
806 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 807 }
769 } 808 }
770 809
@@ -839,15 +878,6 @@ public sealed class BSPrim : BSPhysObject
839 } 878 }
840 public override OMV.Vector3 RotationalVelocity { 879 public override OMV.Vector3 RotationalVelocity {
841 get { 880 get {
842 /*
843 OMV.Vector3 pv = OMV.Vector3.Zero;
844 // if close to zero, report zero
845 // This is copied from ODE but I'm not sure why it returns zero but doesn't
846 // zero the property in the physics engine.
847 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
848 return pv;
849 */
850
851 return _rotationalVelocity; 881 return _rotationalVelocity;
852 } 882 }
853 set { 883 set {
@@ -856,7 +886,8 @@ public sealed class BSPrim : BSPhysObject
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 886 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 887 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 888 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 889 if (PhysBody.HasPhysicalBody)
890 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
860 }); 891 });
861 } 892 }
862 } 893 }
@@ -891,8 +922,11 @@ public sealed class BSPrim : BSPhysObject
891 _buoyancy = value; 922 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 923 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 924 // Buoyancy is faked by changing the gravity applied to the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 925 if (PhysBody.HasPhysicalBody)
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 926 {
927 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
928 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
929 }
896 } 930 }
897 } 931 }
898 932
@@ -960,7 +994,8 @@ public sealed class BSPrim : BSPhysObject
960 } 994 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 995 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
962 if (fSum != OMV.Vector3.Zero) 996 if (fSum != OMV.Vector3.Zero)
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 997 if (PhysBody.HasPhysicalBody)
998 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
964 }); 999 });
965 } 1000 }
966 1001
@@ -971,7 +1006,8 @@ public sealed class BSPrim : BSPhysObject
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() 1006 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1007 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1008 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1009 if (PhysBody.HasPhysicalBody)
1010 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
975 }); 1011 });
976 } 1012 }
977 1013
@@ -1007,18 +1043,23 @@ public sealed class BSPrim : BSPhysObject
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); 1043 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero) 1044 if (fSum != OMV.Vector3.Zero)
1009 { 1045 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); 1046 if (PhysBody.HasPhysicalBody)
1047 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum; 1048 _torque = fSum;
1012 } 1049 }
1013 }); 1050 });
1014 } 1051 }
1015 // A torque impulse. 1052 // A torque impulse.
1053 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1054 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1055 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1056 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1057 {
1018 OMV.Vector3 applyImpulse = impulse; 1058 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1059 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1060 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1061 if (PhysBody.HasPhysicalBody)
1062 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1022 }); 1063 });
1023 } 1064 }
1024 1065
@@ -1326,7 +1367,7 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1367 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1368 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1369 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1370 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1371 {
1331 // If this prim is part of a linkset, we must remove and restore the physical 1372 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt. 1373 // links if the body is rebuilt.
@@ -1336,12 +1377,11 @@ public sealed class BSPrim : BSPhysObject
1336 // Create the correct physical representation for this type of object. 1377 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1378 // Updates PhysBody and PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1379 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed.
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1380 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1381 {
1342 // Called if the current prim body is about to be destroyed. 1382 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1383 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1384 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1385 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1386 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 }); 1387 });
@@ -1381,54 +1421,16 @@ public sealed class BSPrim : BSPhysObject
1381 1421
1382 public override void UpdateProperties(EntityProperties entprop) 1422 public override void UpdateProperties(EntityProperties entprop)
1383 { 1423 {
1384 /* 1424 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1425 if (Linkset.IsRoot(this))
1386 // assign to the local variables so the normal set action does not happen
1387 // if (_position != entprop.Position)
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1389 {
1390 _position = entprop.Position;
1391 changed |= UpdatedProperties.Position;
1392 }
1393 // if (_orientation != entprop.Rotation)
1394 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1395 {
1396 _orientation = entprop.Rotation;
1397 changed |= UpdatedProperties.Rotation;
1398 }
1399 // if (_velocity != entprop.Velocity)
1400 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1401 {
1402 _velocity = entprop.Velocity;
1403 changed |= UpdatedProperties.Velocity;
1404 }
1405 // if (_acceleration != entprop.Acceleration)
1406 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1407 {
1408 _acceleration = entprop.Acceleration;
1409 changed |= UpdatedProperties.Acceleration;
1410 }
1411 // if (_rotationalVelocity != entprop.RotationalVelocity)
1412 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1413 {
1414 _rotationalVelocity = entprop.RotationalVelocity;
1415 changed |= UpdatedProperties.RotationalVel;
1416 }
1417 if (changed != 0)
1418 { 1426 {
1419 // Only update the position of single objects and linkset roots 1427 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1428 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1429 if (_vehicle.IsActive)
1421 { 1430 {
1422 base.RequestPhysicsterseUpdate(); 1431 entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1432 }
1424 }
1425 */
1426
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1428 1433
1429 // Updates only for individual prims and for the root object of a linkset.
1430 if (Linkset.IsRoot(this))
1431 {
1432 // Assign directly to the local variables so the normal set action does not happen 1434 // Assign directly to the local variables so the normal set action does not happen
1433 _position = entprop.Position; 1435 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1436 _orientation = entprop.Rotation;
@@ -1437,21 +1439,19 @@ public sealed class BSPrim : BSPhysObject
1437 _rotationalVelocity = entprop.RotationalVelocity; 1439 _rotationalVelocity = entprop.RotationalVelocity;
1438 1440
1439 // The sanity check can change the velocity and/or position. 1441 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true)) 1442 if (IsPhysical && PositionSanityCheck(true))
1441 { 1443 {
1442 entprop.Position = _position; 1444 entprop.Position = _position;
1443 entprop.Velocity = _velocity; 1445 entprop.Velocity = _velocity;
1444 } 1446 }
1445 1447
1446 // remember the current and last set values 1448 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1447 LastEntityProperties = CurrentEntityProperties;
1448 CurrentEntityProperties = entprop;
1449
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1449 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); 1450 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453 1451
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1452 // remember the current and last set values
1453 LastEntityProperties = CurrentEntityProperties;
1454 CurrentEntityProperties = entprop;
1455 1455
1456 base.RequestPhysicsterseUpdate(); 1456 base.RequestPhysicsterseUpdate();
1457 } 1457 }
@@ -1466,7 +1466,7 @@ public sealed class BSPrim : BSPhysObject
1466 */ 1466 */
1467 1467
1468 // The linkset implimentation might want to know about this. 1468 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this); 1469 Linkset.UpdateProperties(this, true);
1470 } 1470 }
1471} 1471}
1472} 1472}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..069cb0d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,23 +39,10 @@ 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// Test sculpties (verified that they don't work)
43// Compute physics FPS reasonably
44// Based on material, set density and friction 42// Based on material, set density and friction
45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
48// At the moment, physical and phantom causes object to drop through the terrain
49// Physical phantom objects and related typing (collision options )
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 43// More efficient memory usage when passing hull information from BSPrim to BulletSim
53// Should prim.link() and prim.delink() membership checking happen at taint time?
54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 44// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
56// Implement LockAngularMotion 45// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
59// Add PID movement operations. What does ScenePresence.MoveToTarget do? 46// Add PID movement operations. What does ScenePresence.MoveToTarget do?
60// Check terrain size. 128 or 127? 47// Check terrain size. 128 or 127?
61// Raycast 48// Raycast
@@ -109,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
109 public long SimulationStep { get { return m_simulationStep; } } 96 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep; 97 private int m_taintsToProcessPerStep;
111 98
99 public delegate void PreStepAction(float timeStep);
100 public event PreStepAction BeforeStep;
101
112 // A value of the time now so all the collision and update routines do not have to get their own 102 // A value of the time now so all the collision and update routines do not have to get their own
113 // Set to 'now' just before all the prims and actors are called for collisions and updates 103 // Set to 'now' just before all the prims and actors are called for collisions and updates
114 public int SimulationNowTime { get; private set; } 104 public int SimulationNowTime { get; private set; }
@@ -140,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
140 public const uint GROUNDPLANE_ID = 1; 130 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 131 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142 132
143 private float m_waterLevel; 133 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; } 134 public BSTerrainManager TerrainManager { get; private set; }
145 135
146 public ConfigurationParameters Params 136 public ConfigurationParameters Params
@@ -195,8 +185,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
195 private string m_physicsLoggingDir; 185 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix; 186 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes; 187 private int m_physicsLoggingFileMinutes;
188 private bool m_physicsLoggingDoFlush;
198 // 'true' of the vehicle code is to log lots of details 189 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; } 190 public bool VehicleLoggingEnabled { get; private set; }
191 public bool VehiclePhysicalLoggingEnabled { get; private set; }
200 192
201 #region Construction and Initialization 193 #region Construction and Initialization
202 public BSScene(string identifier) 194 public BSScene(string identifier)
@@ -234,6 +226,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 226 if (m_physicsLoggingEnabled)
235 { 227 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 228 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
229 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 230 }
238 else 231 else
239 { 232 {
@@ -302,12 +295,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 295 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 296 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 297 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
298 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
305 // Very detailed logging for vehicle debugging 299 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 300 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
301 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
307 302
308 // Do any replacements in the parameters 303 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 304 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 305 }
306
307 // The material characteristics.
308 BSMaterials.InitializeFromDefaults(Params);
309 if (pConfig != null)
310 {
311 // Let the user add new and interesting material property values.
312 BSMaterials.InitializefromParameters(pConfig);
313 }
311 } 314 }
312 } 315 }
313 316
@@ -345,8 +348,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
345 // make sure no stepping happens while we're deleting stuff 348 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false; 349 m_initialized = false;
347 350
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 351 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 { 352 {
352 kvp.Value.Destroy(); 353 kvp.Value.Destroy();
@@ -366,6 +367,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
366 Shapes = null; 367 Shapes = null;
367 } 368 }
368 369
370 if (TerrainManager != null)
371 {
372 TerrainManager.ReleaseGroundPlaneAndTerrain();
373 TerrainManager.Dispose();
374 TerrainManager = null;
375 }
376
369 // Anything left in the unmanaged code should be cleaned out 377 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr); 378 BulletSimAPI.Shutdown2(World.ptr);
371 379
@@ -490,8 +498,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
490 ProcessTaints(); 498 ProcessTaints();
491 499
492 // Some of the prims operate with special vehicle properties 500 // Some of the prims operate with special vehicle properties
493 ProcessVehicles(timeStep); 501 DoPreStepActions(timeStep);
494 ProcessTaints(); // the vehicles might have added taints 502
503 // the prestep actions might have added taints
504 ProcessTaints();
495 505
496 // step the physical world one interval 506 // step the physical world one interval
497 m_simulationStep++; 507 m_simulationStep++;
@@ -499,16 +509,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
499 509
500 try 510 try
501 { 511 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 512 if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 513 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
504 514
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 515 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 516 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
507 517
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 518 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 519 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 520 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 521 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
522 if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
512 } 523 }
513 catch (Exception e) 524 catch (Exception e)
514 { 525 {
@@ -520,9 +531,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 531 collidersCount = 0;
521 } 532 }
522 533
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 534 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
524 535
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 536 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 537 SimulationNowTime = Util.EnvironmentTickCount();
527 538
528 // If there were collisions, process them by sending the event to the prim. 539 // If there were collisions, process them by sending the event to the prim.
@@ -562,12 +573,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 573
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 574 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 575 // Not done above because it is inside an iteration of ObjectWithCollisions.
576 // This complex collision processing is required to create an empty collision
577 // event call after all collisions have happened on an object. This enables
578 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 579 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 580 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 581 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 582 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 583 ObjectsWithNoMoreCollisions.Clear();
570 } 584 }
585 // Done with collisions.
571 586
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 587 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 588 if (updatedEntityCount > 0)
@@ -585,15 +600,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
585 600
586 ProcessPostStepTaints(); 601 ProcessPostStepTaints();
587 602
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 603 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
589 // Only enable this in a limited test world with few objects. 604 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 605 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
591 606
592 // The physics engine returns the number of milliseconds it simulated this call. 607 // The physics engine returns the number of milliseconds it simulated this call.
593 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 608 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
594 // We multiply by 55 to give a recognizable running rate (55 or less). 609 // Multiply by 55 to give a nominal frame rate of 55.
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 610 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
596 // return timeStep * 1000 * 55;
597 } 611 }
598 612
599 // Something has collided 613 // Something has collided
@@ -639,12 +653,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 653
640 public override void SetWaterLevel(float baseheight) 654 public override void SetWaterLevel(float baseheight)
641 { 655 {
642 m_waterLevel = baseheight; 656 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 657 }
649 658
650 public override void DeleteTerrain() 659 public override void DeleteTerrain()
@@ -915,6 +924,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
915 } 924 }
916 } 925 }
917 926
927 private void DoPreStepActions(float timeStep)
928 {
929 ProcessVehicles(timeStep);
930
931 PreStepAction actions = BeforeStep;
932 if (actions != null)
933 actions(timeStep);
934
935 }
936
918 // Some prims have extra vehicle actions 937 // Some prims have extra vehicle actions
919 // Called at taint time! 938 // Called at taint time!
920 private void ProcessVehicles(float timeStep) 939 private void ProcessVehicles(float timeStep)
@@ -979,6 +998,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
979 // Should handle fetching the right type from the ini file and converting it. 998 // Should handle fetching the right type from the ini file and converting it.
980 // -- a delegate for getting the value as a float 999 // -- a delegate for getting the value as a float
981 // -- a delegate for setting the value from a float 1000 // -- a delegate for setting the value from a float
1001 // -- an optional delegate to update the value in the world. Most often used to
1002 // push the new value to an in-world object.
982 // 1003 //
983 // The single letter parameters for the delegates are: 1004 // The single letter parameters for the delegates are:
984 // s = BSScene 1005 // s = BSScene
@@ -1069,7 +1090,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1069 (s,p,l,v) => { s.PID_P = v; } ), 1090 (s,p,l,v) => { s.PID_P = v; } ),
1070 1091
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 1092 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f, 1093 0.2f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, 1094 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; }, 1095 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), 1096 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
@@ -1084,7 +1105,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1084 (s) => { return s.m_params[0].defaultRestitution; }, 1105 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), 1106 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", 1107 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f, 1108 0.04f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, 1109 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; }, 1110 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), 1111 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
@@ -1151,7 +1172,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1151 (s) => { return s.m_params[0].terrainImplementation; }, 1172 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), 1173 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1174 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1154 0.5f, 1175 0.3f,
1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1176 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1156 (s) => { return s.m_params[0].terrainFriction; }, 1177 (s) => { return s.m_params[0].terrainFriction; },
1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), 1178 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
@@ -1165,13 +1186,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1186 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainRestitution; }, 1187 (s) => { return s.m_params[0].terrainRestitution; },
1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), 1188 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1189 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
1190 0.04f,
1191 (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
1192 (s) => { return s.m_params[0].terrainCollisionMargin; },
1193 (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
1194
1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1195 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1169 0.2f, 1196 0.2f,
1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1197 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarFriction; }, 1198 (s) => { return s.m_params[0].avatarFriction; },
1172 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1199 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1173 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 1200 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1174 10f, 1201 10.0f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, 1202 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; }, 1203 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), 1204 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@@ -1206,6 +1233,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1233 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1234 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1208 1235
1236 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
1237 0.95f,
1238 (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
1239 (s) => { return s.m_params[0].vehicleAngularDamping; },
1240 (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
1209 1241
1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1242 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1211 0f, 1243 0f,
@@ -1487,7 +1519,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1487 { 1519 {
1488 PhysicsLogging.Write(msg, args); 1520 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 1521 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 1522 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 1523 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1524 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 1525 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..d6e2fe9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67 67
68 private bool DDetail = false;
69
68 public BSShapeCollection(BSScene physScene) 70 public BSShapeCollection(BSScene physScene)
69 { 71 {
70 PhysicsScene = physScene; 72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
71 } 78 }
72 79
73 public void Dispose() 80 public void Dispose()
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 126 return ret;
120 } 127 }
121 128
129 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
122 // Track another user of a body. 134 // Track another user of a body.
123 // We presume the caller has allocated the body. 135 // We presume the caller has allocated the body.
124 // Bodies only have one user so the body is just put into the world if not already there. 136 // Bodies only have one user so the body is just put into the world if not already there.
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable
126 { 138 {
127 lock (m_collectionActivityLock) 139 lock (m_collectionActivityLock)
128 { 140 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
131 { 143 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 144 if (!BulletSimAPI.IsInWorld2(body.ptr))
133 { 145 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 146 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 } 148 }
137 }); 149 });
138 } 150 }
@@ -142,14 +154,14 @@ public sealed class BSShapeCollection : IDisposable
142 // Called when releasing use of a BSBody. BSShape is handled separately. 154 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
144 { 156 {
145 if (body.ptr == IntPtr.Zero) 157 if (!body.HasPhysicalBody)
146 return; 158 return;
147 159
148 lock (m_collectionActivityLock) 160 lock (m_collectionActivityLock)
149 { 161 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 163 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body, inTaintTime); 165 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 166 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 167 if (bodyCallback != null) bodyCallback(body);
@@ -157,7 +169,7 @@ public sealed class BSShapeCollection : IDisposable
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 169 if (BulletSimAPI.IsInWorld2(body.ptr))
158 { 170 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 171 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 173 }
162 174
163 // Zero any reference to the shape so it is not freed when the body is deleted. 175 // Zero any reference to the shape so it is not freed when the body is deleted.
@@ -184,7 +196,7 @@ public sealed class BSShapeCollection : IDisposable
184 { 196 {
185 // There is an existing instance of this mesh. 197 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 198 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 201 }
190 else 202 else
@@ -194,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable
194 meshDesc.shapeKey = shape.shapeKey; 206 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 207 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 208 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 211 ret = true;
200 } 212 }
@@ -207,7 +219,7 @@ public sealed class BSShapeCollection : IDisposable
207 { 219 {
208 // There is an existing instance of this hull. 220 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 221 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 224 }
213 else 225 else
@@ -216,7 +228,7 @@ public sealed class BSShapeCollection : IDisposable
216 hullDesc.ptr = shape.ptr; 228 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey; 229 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 230 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 233 ret = true;
222 234
@@ -236,17 +248,17 @@ public sealed class BSShapeCollection : IDisposable
236 // Release the usage of a shape. 248 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
238 { 250 {
239 if (shape.ptr == IntPtr.Zero) 251 if (!shape.HasPhysicalShape)
240 return; 252 return;
241 253
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 255 {
244 if (shape.ptr != IntPtr.Zero) 256 if (shape.HasPhysicalShape)
245 { 257 {
246 if (shape.isNativeShape) 258 if (shape.isNativeShape)
247 { 259 {
248 // Native shapes are not tracked and are released immediately 260 // Native shapes are not tracked and are released immediately
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 262 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape); 263 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 264 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 298 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 299 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 300 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 303
292 } 304 }
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable
307 319
308 hullDesc.lastReferenced = System.DateTime.Now; 320 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 321 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 324 }
313 } 325 }
@@ -325,13 +337,13 @@ public sealed class BSShapeCollection : IDisposable
325 // Failed the sanity check!! 337 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X")); 339 LogHeader, shape.type, shape.ptr.ToString("X"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 341 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return; 342 return;
331 } 343 }
332 344
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 345 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 347
336 for (int ii = numChildren - 1; ii >= 0; ii--) 348 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 349 {
@@ -379,7 +391,7 @@ public sealed class BSShapeCollection : IDisposable
379 } 391 }
380 } 392 }
381 393
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 394 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 395
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 396 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 397 {
@@ -408,19 +420,19 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 421 {
410 // an avatar capsule is close to a native shape (it is not shared) 422 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 423 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 424 FixedShapeKey.KEY_CAPSULE, shapeCallback);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 425 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 426 ret = true;
415 haveShape = true; 427 haveShape = true;
416 } 428 }
417 429
418 // Compound shapes are handled special as they are rebuilt from scratch. 430 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created. 431 // This isn't too great a hardship since most of the child shapes will have already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 432 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 433 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 434 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 435 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 436 haveShape = true;
425 } 437 }
426 438
@@ -433,7 +445,7 @@ public sealed class BSShapeCollection : IDisposable
433 } 445 }
434 446
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 447 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 448 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 449 {
438 bool ret = false; 450 bool ret = false;
439 bool haveShape = false; 451 bool haveShape = false;
@@ -453,19 +465,27 @@ public sealed class BSShapeCollection : IDisposable
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 465 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 466 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 { 467 {
468 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
469 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
470 if (prim.PhysShape.HasPhysicalShape)
471 scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr);
472
473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
474 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
475
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 476 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 477 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 478 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 479 {
460 haveShape = true; 480 haveShape = true;
461 if (forceRebuild 481 if (forceRebuild
462 || prim.Scale != prim.Size 482 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 483 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 484 )
465 { 485 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 486 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 487 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 488 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape); 489 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 490 }
471 } 491 }
@@ -473,13 +493,13 @@ public sealed class BSShapeCollection : IDisposable
473 { 493 {
474 haveShape = true; 494 haveShape = true;
475 if (forceRebuild 495 if (forceRebuild
476 || prim.Scale != prim.Size 496 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 497 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 498 )
479 { 499 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 500 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 501 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 502 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape); 503 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 504 }
485 } 505 }
@@ -504,13 +524,13 @@ public sealed class BSShapeCollection : IDisposable
504 { 524 {
505 // Update prim.BSShape to reference a hull of this shape. 525 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 526 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 529 }
510 else 530 else
511 { 531 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 532 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 535 }
516 return ret; 536 return ret;
@@ -528,9 +548,10 @@ public sealed class BSShapeCollection : IDisposable
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 549
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 552 prim.LocalID, newShape, prim.Scale);
533 553
554 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 555 prim.PhysShape = newShape;
535 return true; 556 return true;
536 } 557 }
@@ -554,16 +575,14 @@ public sealed class BSShapeCollection : IDisposable
554 newShape = new BulletShape( 575 newShape = new BulletShape(
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 576 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
556 , shapeType); 577 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 578 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 579 }
559 else 580 else
560 { 581 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 582 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size;
563 nativeShapeData.Scale = prim.Scale;
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); 583 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 584 }
566 if (newShape.ptr == IntPtr.Zero) 585 if (!newShape.HasPhysicalShape)
567 { 586 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 587 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 588 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 599 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 600 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 601 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 602 BulletShape newShape = new BulletShape();
584 603
585 float lod; 604 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 605 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,7 +608,7 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 608 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 609 return false;
591 610
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 611 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 612 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594 613
595 // Since we're recreating new, get rid of the reference to the previous shape 614 // Since we're recreating new, get rid of the reference to the previous shape
@@ -601,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable
601 620
602 ReferenceShape(newShape); 621 ReferenceShape(newShape);
603 622
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 623 prim.PhysShape = newShape;
607 624
608 return true; // 'true' means a new shape has been added to this prim 625 return true; // 'true' means a new shape has been added to this prim
@@ -620,8 +637,7 @@ public sealed class BSShapeCollection : IDisposable
620 } 637 }
621 else 638 else
622 { 639 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 640 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625 641
626 if (meshData != null) 642 if (meshData != null)
627 { 643 {
@@ -663,7 +679,7 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 679 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 680 return false;
665 681
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 682 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 683 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 684
669 // Remove usage of the previous shape. 685 // Remove usage of the previous shape.
@@ -674,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable
674 690
675 ReferenceShape(newShape); 691 ReferenceShape(newShape);
676 692
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 693 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 694 return true; // 'true' means a new shape has been added to this prim
681 } 695 }
@@ -694,8 +708,8 @@ public sealed class BSShapeCollection : IDisposable
694 else 708 else
695 { 709 {
696 // Build a new hull in the physical world 710 // Build a new hull in the physical world
697 // Pass false for physicalness as this creates some sort of bounding box which we don't need 711 // Pass true for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 712 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 713 if (meshData != null)
700 { 714 {
701 715
@@ -784,7 +798,7 @@ public sealed class BSShapeCollection : IDisposable
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); 798 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 799 newShape.shapeKey = newHullKey;
786 800
787 return newShape; // 'true' means a new shape has been added to this prim 801 return newShape;
788 } 802 }
789 803
790 // Callback from convex hull creater with a newly created hull. 804 // Callback from convex hull creater with a newly created hull.
@@ -809,7 +823,7 @@ public sealed class BSShapeCollection : IDisposable
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 823 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 824 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 825 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 826 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 827 prim.LocalID, cShape, prim.PhysShape);
814 828
815 prim.PhysShape = cShape; 829 prim.PhysShape = cShape;
@@ -851,7 +865,7 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 865 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 866 {
853 // If the shape was successfully created, nothing more to do 867 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 868 if (newShape.HasPhysicalShape)
855 return newShape; 869 return newShape;
856 870
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 871 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@@ -910,7 +924,7 @@ public sealed class BSShapeCollection : IDisposable
910 bool ret = false; 924 bool ret = false;
911 925
912 // the mesh, hull or native shape must have already been created in Bullet 926 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 927 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 928
915 // If there is an existing body, verify it's of an acceptable type. 929 // If there is an existing body, verify it's of an acceptable type.
916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 930 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
@@ -936,13 +950,13 @@ public sealed class BSShapeCollection : IDisposable
936 { 950 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 951 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 952 prim.LocalID, prim.RawPosition, prim.RawOrientation);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 953 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 } 954 }
941 else 955 else
942 { 956 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 957 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 958 prim.LocalID, prim.RawPosition, prim.RawOrientation);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 959 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 } 960 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr); 961 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 962
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756c..2b120d6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
93 { 93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, 94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords, 95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); 96 m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
97 97
98 // Create the terrain shape from the mapInfo 98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
@@ -121,9 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
121 // redo its bounding box now that it is in the world 121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123 123
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, 124 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 (uint)CollisionFilterGroups.TerrainFilter, 125 m_mapInfo.terrainBody.ApplyCollisionMask();
126 (uint)CollisionFilterGroups.TerrainMask);
127 126
128 // Make it so the terrain will not move or be considered for movement. 127 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 128 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@@ -136,7 +135,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
136 { 135 {
137 if (m_mapInfo != null) 136 if (m_mapInfo != null)
138 { 137 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) 138 if (m_mapInfo.terrainBody.HasPhysicalBody)
140 { 139 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 140 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 // Frees both the body and the shape. 141 // Frees both the body and the shape.
@@ -148,7 +147,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
148 } 147 }
149 148
150 // The passed position is relative to the base of the region. 149 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos) 150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
152 { 151 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154 153
@@ -166,5 +165,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
166 } 165 }
167 return ret; 166 return ret;
168 } 167 }
168
169 // The passed position is relative to the base of the region.
170 public override float GetWaterLevelAtXYZ(Vector3 pos)
171 {
172 return PhysicsScene.SimpleWaterLevel;
173 }
169} 174}
170} 175}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd3..3428b9c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable
62 ID = id; 62 ID = id;
63 } 63 }
64 public abstract void Dispose(); 64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos); 65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66} 67}
67 68
68// ========================================================================================== 69// ==========================================================================================
69public sealed class BSTerrainManager 70public sealed class BSTerrainManager : IDisposable
70{ 71{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72 73
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager
75 public const float HEIGHT_INITIALIZATION = 24.987f; 76 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; 77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f; 78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
78 80
79 // If the min and max height are equal, we reduce the min by this 81 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain. 82 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82 84
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants. 85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
@@ -122,6 +122,11 @@ public sealed class BSTerrainManager
122 MegaRegionParentPhysicsScene = null; 122 MegaRegionParentPhysicsScene = null;
123 } 123 }
124 124
125 public void Dispose()
126 {
127 ReleaseGroundPlaneAndTerrain();
128 }
129
125 // Create the initial instance of terrain and the underlying ground plane. 130 // Create the initial instance of terrain and the underlying ground plane.
126 // This is called from the initialization routine so we presume it is 131 // This is called from the initialization routine so we presume it is
127 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
@@ -129,7 +134,8 @@ public sealed class BSTerrainManager
129 { 134 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity 135 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 136 BulletShape groundPlaneShape = new BulletShape(
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 137 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
138 PhysicsScene.Params.terrainCollisionMargin),
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 139 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 140 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 141 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@@ -139,8 +145,8 @@ public sealed class BSTerrainManager
139 // Ground plane does not move 145 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 146 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 147 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 148 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 149 m_groundPlane.ApplyCollisionMask();
144 150
145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 151 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
146 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -150,13 +156,13 @@ public sealed class BSTerrainManager
150 // Release all the terrain structures we might have allocated 156 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 157 public void ReleaseGroundPlaneAndTerrain()
152 { 158 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 159 if (m_groundPlane.HasPhysicalBody)
154 { 160 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 161 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
156 { 162 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 163 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
158 } 164 }
159 m_groundPlane.ptr = IntPtr.Zero; 165 m_groundPlane.Clear();
160 } 166 }
161 167
162 ReleaseTerrain(); 168 ReleaseTerrain();
@@ -165,17 +171,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 171 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 172 public void ReleaseTerrain()
167 { 173 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 174 lock (m_terrains)
169 { 175 {
170 kvp.Value.Dispose(); 176 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
177 {
178 kvp.Value.Dispose();
179 }
180 m_terrains.Clear();
171 } 181 }
172 m_terrains.Clear();
173 } 182 }
174 183
175 // The simulator wants to set a new heightmap for the terrain. 184 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 185 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 186 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 187 // If there are multiple requests for changes to the same terrain between ticks,
188 // only do that last one.
189 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 190 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 191 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 192 {
@@ -211,6 +222,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 222 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain. 223 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.) 224 // (The above does suggest that some simplification/refactoring is in order.)
225 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 226 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 227 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 228 {
@@ -220,7 +232,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 232 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 233 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the 234 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z. 235 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 236 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 237 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 238 foreach (float height in heightMap)
@@ -238,15 +250,15 @@ public sealed class BSTerrainManager
238 250
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 251 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 252
241 BSTerrainPhys terrainPhys; 253 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 254 {
244 // There is already a terrain in this spot. Free the old and build the new. 255 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 256 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 257 {
258 // There is already a terrain in this spot. Free the old and build the new.
259 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
260 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
261
250 // Remove old terrain from the collection 262 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 263 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 264 // Release any physical memory it may be using.
@@ -271,35 +283,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 283 // I hate doing this, but just bail
272 return; 284 return;
273 } 285 }
274 }); 286 }
275 } 287 else
276 else 288 {
277 { 289 // We don't know about this terrain so either we are creating a new terrain or
278 // We don't know about this terrain so either we are creating a new terrain or 290 // our mega-prim child is giving us a new terrain to add to the phys world
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289 291
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 292 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 293 uint newTerrainID = id;
294 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
295 newTerrainID = ++m_terrainCount;
292 296
293 // Code that must happen at taint-time 297 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 298 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 299 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 300 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 301
301 m_terrainModified = true; 302 m_terrainModified = true;
302 }); 303 }
303 } 304 }
304 } 305 }
305 306
@@ -331,6 +332,13 @@ public sealed class BSTerrainManager
331 return newTerrainPhys; 332 return newTerrainPhys;
332 } 333 }
333 334
335 // Return 'true' of this position is somewhere in known physical terrain space
336 public bool IsWithinKnownTerrain(Vector3 pos)
337 {
338 Vector3 terrainBaseXYZ;
339 BSTerrainPhys physTerrain;
340 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
341 }
334 342
335 // Given an X and Y, find the height of the terrain. 343 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 344 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +349,74 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 349 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 350 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 351 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 352 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 353 {
346 float tX = loc.X; 354 float tX = pos.X;
347 float tY = loc.Y; 355 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 356 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 357 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 358 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 359 return lastHeight;
360 m_terrainModified = false;
352 361
353 lastHeightTX = tX; 362 lastHeightTX = tX;
354 lastHeightTY = tY; 363 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 364 float ret = HEIGHT_GETHEIGHT_RET;
356 365
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 366 Vector3 terrainBaseXYZ;
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360
361 BSTerrainPhys physTerrain; 367 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 368 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 369 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 370 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 371 }
368 else 372 else
369 { 373 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 374 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 375 LogHeader, PhysicsScene.RegionName, tX, tY);
376 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
377 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 378 }
373 m_terrainModified = false; 379
374 lastHeight = ret; 380 lastHeight = ret;
375 return ret; 381 return ret;
376 } 382 }
377 383
384 public float GetWaterLevelAtXYZ(Vector3 pos)
385 {
386 float ret = WATER_HEIGHT_GETHEIGHT_RET;
387
388 Vector3 terrainBaseXYZ;
389 BSTerrainPhys physTerrain;
390 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
391 {
392 ret = physTerrain.GetWaterLevelAtXYZ(pos);
393 }
394 else
395 {
396 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
397 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
398 }
399 return ret;
400 }
401
402 // Given an address, return 'true' of there is a description of that terrain and output
403 // the descriptor class and the 'base' fo the addresses therein.
404 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
405 {
406 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
407 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
408 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
409
410 BSTerrainPhys physTerrain = null;
411 lock (m_terrains)
412 {
413 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
414 }
415 outTerrainBase = terrainBaseXYZ;
416 outPhysTerrain = physTerrain;
417 return (physTerrain != null);
418 }
419
378 // Although no one seems to check this, I do support combining. 420 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 421 public bool SupportsCombining()
380 { 422 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..6dc0d92 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,11 +88,13 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices), 95 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH); 96 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero) 97 if (!m_terrainShape.HasPhysicalShape)
96 { 98 {
97 // DISASTER!! 99 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@@ -105,7 +107,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
105 Quaternion rot = Quaternion.Identity; 107 Quaternion rot = Quaternion.Identity;
106 108
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
108 if (m_terrainBody.ptr == IntPtr.Zero) 110 if (!m_terrainBody.HasPhysicalBody)
109 { 111 {
110 // DISASTER!! 112 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@@ -122,15 +124,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys
122 // Static objects are not very massive. 124 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124 126
125 // Return the new terrain to the world of physical objects 127 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127 129
128 // redo its bounding box now that it is in the world 130 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130 132
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 133 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 134 m_terrainBody.ApplyCollisionMask();
133 (uint)CollisionFilterGroups.TerrainMask);
134 135
135 // Make it so the terrain will not move or be considered for movement. 136 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 137 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
@@ -138,7 +139,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
138 139
139 public override void Dispose() 140 public override void Dispose()
140 { 141 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 142 if (m_terrainBody.HasPhysicalBody)
142 { 143 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
144 // Frees both the body and the shape. 145 // Frees both the body and the shape.
@@ -146,7 +147,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
146 } 147 }
147 } 148 }
148 149
149 public override float GetHeightAtXYZ(Vector3 pos) 150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 151 {
151 // For the moment use the saved heightmap to get the terrain height. 152 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 153 // TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +168,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 168 return ret;
168 } 169 }
169 170
171 // The passed position is relative to the base of the region.
172 public override float GetWaterLevelAtXYZ(Vector3 pos)
173 {
174 return PhysicsScene.SimpleWaterLevel;
175 }
176
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 177 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 178 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 179 public static bool ConvertHeightmapToMesh(
@@ -188,6 +195,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 195 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 196 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 197
198 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
199 // from zero to <= sizeX). The triangle indices are then generated as two triangles
200 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
201 // column of vertices are used to complete the triangles of the last row and column
202 // of the heightmap.
191 try 203 try
192 { 204 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 205 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +212,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 212 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 213 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 214 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
215 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 216 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++) 217 for (int yy = 0; yy <= sizeY; yy++)
205 { 218 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 219 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 220 {
208 int offset = yy * sizeX + xx; 221 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 222 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 223 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 224 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 225 float height = heightMap[offset];
226 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 227 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 228 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 229 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -217,14 +231,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
217 } 231 }
218 } 232 }
219 verticesCount = verticesCount / 3; 233 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 234
223 for (int yy = 0; yy < sizeY; yy++) 235 for (int yy = 0; yy < sizeY; yy++)
224 { 236 {
225 for (int xx = 0; xx < sizeX; xx++) 237 for (int xx = 0; xx < sizeX; xx++)
226 { 238 {
227 int offset = yy * sizeX + xx; 239 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 240 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 241 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 242 indices[indicesCount + 1] = offset + 1;
@@ -235,8 +247,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 247 indicesCount += 6;
236 } 248 }
237 } 249 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 250
239 LogHeader, indicesCount); // DEBUG
240 ret = true; 251 ret = true;
241 } 252 }
242 catch (Exception e) 253 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index e60a760..962b540 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic;
28using System.Runtime.InteropServices; 29using System.Runtime.InteropServices;
29using System.Security; 30using System.Security;
30using System.Text; 31using System.Text;
@@ -32,93 +33,6 @@ using OpenMetaverse;
32 33
33namespace OpenSim.Region.Physics.BulletSPlugin { 34namespace OpenSim.Region.Physics.BulletSPlugin {
34 35
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
39public struct BulletSim
40{
41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
49 // The scene is only in here so very low level routines have a handle to print debug/error messages
50 public BSScene physicsScene;
51}
52
53// An allocated Bullet btRigidBody
54public struct BulletBody
55{
56 public BulletBody(uint id, IntPtr xx)
57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
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=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public BSPhysicsShapeType 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 }
120}
121
122 // Constraint type values as defined by Bullet 36 // Constraint type values as defined by Bullet
123public enum ConstraintType : int 37public enum ConstraintType : int
124{ 38{
@@ -132,44 +46,6 @@ public enum ConstraintType : int
132 MAX_CONSTRAINT_TYPE 46 MAX_CONSTRAINT_TYPE
133} 47}
134 48
135// An allocated Bullet btConstraint
136public struct BulletConstraint
137{
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 = Vector3.Zero;
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;
162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector3 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;
171}
172
173// =============================================================================== 49// ===============================================================================
174[StructLayout(LayoutKind.Sequential)] 50[StructLayout(LayoutKind.Sequential)]
175public struct ConvexHull 51public struct ConvexHull
@@ -287,6 +163,8 @@ public struct ConfigurationParameters
287 public float terrainFriction; 163 public float terrainFriction;
288 public float terrainHitFraction; 164 public float terrainHitFraction;
289 public float terrainRestitution; 165 public float terrainRestitution;
166 public float terrainCollisionMargin;
167
290 public float avatarFriction; 168 public float avatarFriction;
291 public float avatarStandingFriction; 169 public float avatarStandingFriction;
292 public float avatarDensity; 170 public float avatarDensity;
@@ -296,6 +174,8 @@ public struct ConfigurationParameters
296 public float avatarCapsuleHeight; 174 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold; 175 public float avatarContactProcessingThreshold;
298 176
177 public float vehicleAngularDamping;
178
299 public float maxPersistantManifoldPoolSize; 179 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize; 180 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation; 181 public float shouldDisableContactPoolDynamicAllocation;
@@ -353,56 +233,35 @@ public enum CollisionFlags : uint
353 CF_CHARACTER_OBJECT = 1 << 4, 233 CF_CHARACTER_OBJECT = 1 << 4,
354 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 234 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 235 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
356 // Following used by BulletSim to control collisions 236 // Following used by BulletSim to control collisions and updates
357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 237 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
358 BS_FLOATS_ON_WATER = 1 << 11, 238 BS_FLOATS_ON_WATER = 1 << 11,
239 BS_VEHICLE_COLLISIONS = 1 << 12,
359 BS_NONE = 0, 240 BS_NONE = 0,
360 BS_ALL = 0xFFFFFFFF, 241 BS_ALL = 0xFFFFFFFF
361
362 // These are the collision flags switched depending on physical state.
363 // The other flags are used for other things and should not be fooled with.
364 BS_ACTIVE = CF_STATIC_OBJECT
365 | CF_KINEMATIC_OBJECT
366 | CF_NO_CONTACT_RESPONSE
367}; 242};
368 243
369// Values for collisions groups and masks 244// Values f collisions groups and masks
370public enum CollisionFilterGroups : uint 245public enum CollisionFilterGroups : uint
371{ 246{
372 // Don't use the bit definitions!! Define the use in a 247 // Don't use the bit definitions!! Define the use in a
373 // filter/mask definition below. This way collision interactions 248 // filter/mask definition below. This way collision interactions
374 // are more easily debugged. 249 // are more easily found and debugged.
375 BNoneFilter = 0, 250 BNoneGroup = 0,
376 BDefaultFilter = 1 << 0, 251 BDefaultGroup = 1 << 0,
377 BStaticFilter = 1 << 1, 252 BStaticGroup = 1 << 1,
378 BKinematicFilter = 1 << 2, 253 BKinematicGroup = 1 << 2,
379 BDebrisFilter = 1 << 3, 254 BDebrisGroup = 1 << 3,
380 BSensorTrigger = 1 << 4, 255 BSensorTrigger = 1 << 4,
381 BCharacterFilter = 1 << 5, 256 BCharacterGroup = 1 << 5,
382 BAllFilter = 0xFFFFFFFF, 257 BAllGroup = 0xFFFFFFFF,
383 // Filter groups defined by BulletSim 258 // Filter groups defined by BulletSim
384 BGroundPlaneFilter = 1 << 10, 259 BGroundPlaneGroup = 1 << 10,
385 BTerrainFilter = 1 << 11, 260 BTerrainGroup = 1 << 11,
386 BRaycastFilter = 1 << 12, 261 BRaycastGroup = 1 << 12,
387 BSolidFilter = 1 << 13, 262 BSolidGroup = 1 << 13,
388 BLinksetFilter = 1 << 14, 263 // BLinksetGroup = xx // a linkset proper is either static or dynamic
389 264 BLinksetChildGroup = 1 << 14,
390 // The collsion filters and masked are defined in one place -- don't want them scattered
391 AvatarFilter = BCharacterFilter,
392 AvatarMask = BAllFilter,
393 ObjectFilter = BSolidFilter,
394 ObjectMask = BAllFilter,
395 StaticObjectFilter = BStaticFilter,
396 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
397 LinksetFilter = BLinksetFilter,
398 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
399 VolumeDetectFilter = BSensorTrigger,
400 VolumeDetectMask = ~BSensorTrigger,
401 TerrainFilter = BTerrainFilter,
402 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
403 GroundPlaneFilter = BGroundPlaneFilter,
404 GroundPlaneMask = BAllFilter
405
406}; 265};
407 266
408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 267// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -429,7 +288,7 @@ public enum ConstraintParamAxis : int
429 288
430// =============================================================================== 289// ===============================================================================
431static class BulletSimAPI { 290static class BulletSimAPI {
432 291// ===============================================================================
433// Link back to the managed code for outputting log messages 292// Link back to the managed code for outputting log messages
434[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 293[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 294public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
@@ -482,6 +341,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
482public static extern bool IsNativeShape2(IntPtr shape); 341public static extern bool IsNativeShape2(IntPtr shape);
483 342
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 343[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
344public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
345
346[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 347public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
486 348
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 349[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -938,7 +800,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
938public static extern int GetNumConstraintRefs2(IntPtr obj); 800public static extern int GetNumConstraintRefs2(IntPtr obj);
939 801
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 802[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); 803public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
942 804
943// ===================================================================================== 805// =====================================================================================
944// btCollisionShape entries 806// btCollisionShape entries
@@ -1000,13 +862,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1000public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); 862public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1001 863
1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
865public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
866
867[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1003public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); 868public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1004 869
1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 870[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1006public static extern void DumpAllInfo2(IntPtr sim); 871public static extern void DumpActivationInfo2(IntPtr sim);
1007 872
1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 873[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1009public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); 874public static extern void DumpAllInfo2(IntPtr sim);
1010 875
1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1012public static extern void DumpPhysicsStatistics2(IntPtr sim); 877public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
new file mode 100755
index 0000000..662177f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,278 @@
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;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36
37// The physics engine controller class created at initialization
38public struct BulletSim
39{
40 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
41 {
42 ptr = xx;
43 worldID = worldId;
44 physicsScene = bss;
45 }
46 public IntPtr ptr;
47 public uint worldID;
48 // The scene is only in here so very low level routines have a handle to print debug/error messages
49 public BSScene physicsScene;
50}
51
52// An allocated Bullet btRigidBody
53public struct BulletBody
54{
55 public BulletBody(uint id) : this(id, IntPtr.Zero)
56 {
57 }
58 public BulletBody(uint id, IntPtr xx)
59 {
60 ID = id;
61 ptr = xx;
62 collisionType = CollisionType.Static;
63 }
64 public IntPtr ptr;
65 public uint ID;
66 public CollisionType collisionType;
67
68 public void Clear()
69 {
70 ptr = IntPtr.Zero;
71 }
72 public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } }
73
74 // Apply the specificed collision mask into the physical world
75 public void ApplyCollisionMask()
76 {
77 // Should assert the body has been added to the physical world.
78 // (The collision masks are stored in the collision proxy cache which only exists for
79 // a collision body that is in the world.)
80 BulletSimAPI.SetCollisionGroupMask2(ptr,
81 BulletSimData.CollisionTypeMasks[collisionType].group,
82 BulletSimData.CollisionTypeMasks[collisionType].mask);
83 }
84
85 public override string ToString()
86 {
87 StringBuilder buff = new StringBuilder();
88 buff.Append("<id=");
89 buff.Append(ID.ToString());
90 buff.Append(",p=");
91 buff.Append(ptr.ToString("X"));
92 buff.Append(",c=");
93 buff.Append(collisionType);
94 buff.Append(">");
95 return buff.ToString();
96 }
97}
98
99public struct BulletShape
100{
101 public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
102 {
103 }
104 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
105 {
106 ptr = xx;
107 type = typ;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public IntPtr ptr;
112 public BSPhysicsShapeType type;
113 public System.UInt64 shapeKey;
114 public bool isNativeShape;
115
116 public void Clear()
117 {
118 ptr = IntPtr.Zero;
119 }
120 public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } }
121
122 public override string ToString()
123 {
124 StringBuilder buff = new StringBuilder();
125 buff.Append("<p=");
126 buff.Append(ptr.ToString("X"));
127 buff.Append(",s=");
128 buff.Append(type.ToString());
129 buff.Append(",k=");
130 buff.Append(shapeKey.ToString("X"));
131 buff.Append(",n=");
132 buff.Append(isNativeShape.ToString());
133 buff.Append(">");
134 return buff.ToString();
135 }
136}
137
138// An allocated Bullet btConstraint
139public struct BulletConstraint
140{
141 public BulletConstraint(IntPtr xx)
142 {
143 ptr = xx;
144 }
145 public IntPtr ptr;
146
147 public void Clear()
148 {
149 ptr = IntPtr.Zero;
150 }
151 public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
152}
153
154// An allocated HeightMapThing which holds various heightmap info.
155// Made a class rather than a struct so there would be only one
156// instance of this and C# will pass around pointers rather
157// than making copies.
158public class BulletHeightMapInfo
159{
160 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
161 ID = id;
162 Ptr = xx;
163 heightMap = hm;
164 terrainRegionBase = OMV.Vector3.Zero;
165 minCoords = new OMV.Vector3(100f, 100f, 25f);
166 maxCoords = new OMV.Vector3(101f, 101f, 26f);
167 minZ = maxZ = 0f;
168 sizeX = sizeY = 256f;
169 }
170 public uint ID;
171 public IntPtr Ptr;
172 public float[] heightMap;
173 public OMV.Vector3 terrainRegionBase;
174 public OMV.Vector3 minCoords;
175 public OMV.Vector3 maxCoords;
176 public float sizeX, sizeY;
177 public float minZ, maxZ;
178 public BulletShape terrainShape;
179 public BulletBody terrainBody;
180}
181
182// The general class of collsion object.
183public enum CollisionType
184{
185 Avatar,
186 Groundplane,
187 Terrain,
188 Static,
189 Dynamic,
190 VolumeDetect,
191 // Linkset, // A linkset should be either Static or Dynamic
192 LinksetChild,
193 Unknown
194};
195
196// Hold specification of group and mask collision flags for a CollisionType
197public struct CollisionTypeFilterGroup
198{
199 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
200 {
201 type = t;
202 group = g;
203 mask = m;
204 }
205 public CollisionType type;
206 public uint group;
207 public uint mask;
208};
209
210 /* NOTE: old definitions kept for reference. Delete when things are working.
211 // The collsion filters and masked are defined in one place -- don't want them scattered
212 AvatarGroup = BCharacterGroup,
213 AvatarMask = BAllGroup,
214 ObjectGroup = BSolidGroup,
215 ObjectMask = BAllGroup,
216 StaticObjectGroup = BStaticGroup,
217 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
218 LinksetGroup = BLinksetGroup,
219 LinksetMask = BAllGroup,
220 LinksetChildGroup = BLinksetChildGroup,
221 LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
222 VolumeDetectGroup = BSensorTrigger,
223 VolumeDetectMask = ~BSensorTrigger,
224 TerrainGroup = BTerrainGroup,
225 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
226 GroundPlaneGroup = BGroundPlaneGroup,
227 GroundPlaneMask = BAllGroup
228 */
229
230public static class BulletSimData
231{
232
233// Map of collisionTypes to flags for collision groups and masks.
234// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
235// but, instead, use references to this dictionary. Finding and debugging
236// collision flag problems will be made easier.
237public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
238 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
239{
240 { CollisionType.Avatar,
241 new CollisionTypeFilterGroup(CollisionType.Avatar,
242 (uint)CollisionFilterGroups.BCharacterGroup,
243 (uint)CollisionFilterGroups.BAllGroup)
244 },
245 { CollisionType.Groundplane,
246 new CollisionTypeFilterGroup(CollisionType.Groundplane,
247 (uint)CollisionFilterGroups.BGroundPlaneGroup,
248 (uint)CollisionFilterGroups.BAllGroup)
249 },
250 { CollisionType.Terrain,
251 new CollisionTypeFilterGroup(CollisionType.Terrain,
252 (uint)CollisionFilterGroups.BTerrainGroup,
253 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
254 },
255 { CollisionType.Static,
256 new CollisionTypeFilterGroup(CollisionType.Static,
257 (uint)CollisionFilterGroups.BStaticGroup,
258 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 },
260 { CollisionType.Dynamic,
261 new CollisionTypeFilterGroup(CollisionType.Dynamic,
262 (uint)CollisionFilterGroups.BSolidGroup,
263 (uint)(CollisionFilterGroups.BAllGroup))
264 },
265 { CollisionType.VolumeDetect,
266 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
267 (uint)CollisionFilterGroups.BSensorTrigger,
268 (uint)(~CollisionFilterGroups.BSensorTrigger))
269 },
270 { CollisionType.LinksetChild,
271 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
272 (uint)CollisionFilterGroups.BTerrainGroup,
273 (uint)(CollisionFilterGroups.BNoneGroup))
274 },
275};
276
277}
278}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..0d9a156
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,204 @@
1CURRENT PRIORITIES
2=================================================
3Eliminate all crashes (DONEish)
4 Editing/deleting physical linkset (DONE)
5 Border crossing of physical linkset (DONE)
6Enable vehicle border crossings (at least as poorly as ODE)
7 Avatar created in previous region and not new region when crossing border
8 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
9Calibrate turning radius
10limitMotorUp calibration (more down?)
11study PID motors (include 'efficiency' implementation
12 Add to avatar movement
13
14CRASHES
15=================================================
1620121129.1411: editting/moving phys object across region boundries causes crash
17 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
1820121128.1600: mesh object not rezzing (no physics mesh).
19 Causes many errors. Doesn't stop after first error with box shape.
20 Eventually crashes when deleting the object.
2120121206.1434: rez Sam-pan into OSGrid BulletSim11 region
22 Immediate simulator crash. Mono does not output any stacktrace and
23 log just stops after reporting taint-time linking of the linkset.
24
25VEHICLES TODO LIST:
26=================================================
27Border crossing with linked vehicle causes crash
28Neb vehicle taking > 25ms of physics time!!
29Vehicles (Move smoothly)
30Add vehicle collisions so IsColliding is properly reported.
31 Needed for banking, limitMotorUp, movementLimiting, ...
32Some vehicles should not be able to turn if no speed or off ground.
33Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
34Neb car jiggling left and right
35 Happens on terrain and any other mesh object. Flat cubes are much smoother.
36 This has been reduced but not eliminated.
37Light cycle falling over when driving
38Implement referenceFrame for all the motion routines.
39Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
40 Verify that angular motion specified around Z moves in the vehicle coordinates.
41Verify llGetVel() is returning a smooth and good value for vehicle movement.
42llGetVel() should return the root's velocity if requested in a child prim.
43Implement function efficiency for lineaar and angular motion.
44Should vehicle angular/linear movement friction happen after all the components
45 or does it only apply to the basic movement?
46After getting off a vehicle, the root prim is phantom (can be walked through)
47 Need to force a position update for the root prim after compound shape destruction
48Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
49For limitMotorUp, use raycast down to find if vehicle is in the air.
50Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
51 A kludge that isn't fixing the real problem of Bullet adding extra motion.
52
53BULLETSIM TODO LIST:
54=================================================
55Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
56Avatar height off after unsitting (floats off ground)
57 Editting appearance then moving restores.
58 Must not be initializing height when recreating capsule after unsit.
59Duplicating a physical prim causes old prim to jump away
60 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
61Scenes with hundred of thousands of static objects take a lot of physics CPU time.
62BSPrim.Force should set a continious force on the prim. The force should be
63 applied each tick. Some limits?
64Gun sending shooter flying.
65Collision margin (gap between physical objects lying on each other)
66Boundry checking (crashes related to crossing boundry)
67 Add check for border edge position for avatars and objects.
68 Verify the events are created for border crossings.
69Avatar rotation (check out changes to ScenePresence for physical rotation)
70Avatar running (what does phys engine need to do?)
71Small physical objects do not interact correctly
72 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
73 The chain will fall apart and pairs will dance around on ground
74 Chains of 1x1x.2 will stay connected but will dance.
75 Chains above 2x2x.4 are move stable and get stablier as torui get larger.
76Add PID motor for avatar movement (slow to stop, ...)
77setForce should set a constant force. Different than AddImpulse.
78Implement raycast.
79Implement ShapeCollection.Dispose()
80Implement water as a plain so raycasting and collisions can happen with same.
81Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
82 Also osGetPhysicsEngineVerion() maybe.
83Linkset.Position and Linkset.Orientation requre rewrite to properly return
84 child position. LinksetConstraint acts like it's at taint time!!
85
86LINKSETS
87======================================================
88Linksets should allow collisions to individual children
89 Add LocalID to children shapes in LinksetCompound and create events for individuals
90LinksetCompound: when one of the children changes orientation (like tires
91 turning on a vehicle, the whole compound object is rebuilt. Optimize this
92 so orientation/position of individual children can change without a rebuild.
93Verify/think through scripts in children of linksets. What do they reference
94 and return when getting position, velocity, ...
95Confirm constraint linksets still work after making all the changes for compound linksets.
96Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
97 For compound linksets, add ability to remove or reposition individual child shapes.
98Disable activity of passive linkset children.
99 Since the linkset is a compound object, the old prims are left lying
100 around and need to be phantomized so they don't collide, ...
101Speed up creation of large physical linksets
102 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
103Eliminate collisions between objects in a linkset. (LinksetConstraint)
104 Have UserPointer point to struct with localID and linksetID?
105 Objects in original linkset still collide with each other?
106
107MORE
108======================================================
109Find/remove avatar collision with ID=0.
110Test avatar walking up stairs. How does compare with SL.
111 Radius of the capsule affects ability to climb edges.
112Tune terrain/object friction to be closer to SL.
113Debounce avatar contact so legs don't keep folding up when standing.
114Implement LSL physics controls. Like STATUS_ROTATE_X.
115Add border extensions to terrain to help region crossings and objects leaving region.
116
117Performance test with lots of avatars. Can BulletSim support a thousand?
118Optimize collisions in C++: only send up to the object subscribed to collisions.
119 Use collision subscription and remove the collsion(A,B) and collision(B,A)
120Check whether SimMotionState needs large if statement (see TODO).
121
122Implement 'top colliders' info.
123Avatar jump
124Performance measurement and changes to make quicker.
125Implement detailed physics stats (GetStats()).
126
127Measure performance improvement from hulls
128Test not using ghost objects for volume detect implementation.
129Performance of closures and delegates for taint processing
130 Are there faster ways?
131 Is any slowdown introduced by the existing implementation significant?
132Is there are more efficient method of implementing pre and post step actions?
133 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
134
135Physics Arena central pyramid: why is one side permiable?
136
137INTERNAL IMPROVEMENT/CLEANUP
138=================================================
139Consider moving prim/character body and shape destruction in destroy()
140 to postTimeTime rather than protecting all the potential sets that
141 might have been queued up.
142Remove unused fields from ShapeData (not used in API2)
143Breakout code for mesh/hull/compound/native into separate BSShape* classes
144 Standardize access to building and reference code.
145 The skeleton classes are in the sources but are not complete or linked in.
146Make BSBody and BSShape real classes to centralize creation/changin/destruction
147 Convert state and parameter calls from BulletSimAPI direct calls to
148 calls on BSBody and BSShape
149Generalize Dynamics and PID with standardized motors.
150Generalize Linkset and vehicles into PropertyManagers
151 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
152 Potentially add events for shape destruction, etc.
153Complete implemention of preStepActions
154 Replace vehicle step call with prestep event.
155 Is there a need for postStepActions? postStepTaints?
156Implement linkset by setting position of children when root updated. (LinksetManual)
157 Linkset implementation using manual prim movement.
158LinkablePrim class? Would that simplify/centralize the linkset logic?
159BSScene.UpdateParameterSet() is broken. How to set params on objects?
160Remove HeightmapInfo from terrain specification
161 Since C++ code does not need terrain height, this structure et al are not needed.
162Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
163 bob at the water level. BSPrim.PositionSanityCheck().
164Should taints check for existance or activeness of target?
165 When destroying linksets/etc, taints can be generated for objects that are
166 actually gone when the taint happens. Crashes don't happen because the taint closure
167 keeps the object from being freed, but that is just an accident.
168 Possibly have and 'active' flag that is checked by the taint processor?
169
170THREADING
171=================================================
172Do taint action immediately if not actually executing Bullet.
173 Add lock around Bullet execution and just do taint actions if simulation is not happening.
174
175DONE DONE DONE DONE
176=================================================
177Cleanup code in BSDynamics by using motors. (Resolution: started)
178Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
179 Would have better and adjustable resolution.
180Build terrain mesh so heighmap is height of the center of the square meter.
181 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
182Terrain as mesh. (Resolution: done)
183How are static linksets seen by the physics engine?
184 Resolution: they are not linked in physics. When moved, all the children are repositioned.
185Convert BSCharacter to use all API2 (Resolution: done)
186Avatar pushing difficult (too heavy?)
187Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
188Remove old code in DLL (all non-API2 stuff). (Resolution: done)
189Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
190Debug Bullet internal stats output (why is timing all wrong?)
191 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
192Implement meshes or just verify that they work. (Resolution: they do!)
193Do prim hash codes work for sculpties and meshes? (Resolution: yes)
194Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
195 Compound shapes will need the LocalID in the shapes and collision
196 processing to get it from there.
197Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
198Package Bullet source mods for Bullet internal stats output
199 (Resolution: move code into WorldData.h rather than relying on patches)
200Single prim vehicles don't seem to properly vehiclize.
201 (Resolution: mass was not getting set properly for single prim linksets)
202Add material type linkage and input all the material property definitions.
203 Skeleton classes and table are in the sources but are not filled or used.
204 (Resolution:
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
index 8de70ef..ba24aa7 100644
--- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -2190,7 +2190,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2190 convex = false; 2190 convex = false;
2191 try 2191 try
2192 { 2192 {
2193 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,convex,false); 2193 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, (int)LevelOfDetail.High, true,false,convex,false);
2194 } 2194 }
2195 catch 2195 catch
2196 { 2196 {
@@ -2557,7 +2557,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2557 2557
2558 try 2558 try
2559 { 2559 {
2560 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, convex,false); 2560 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, (int)LevelOfDetail.High, true, false,convex,false);
2561 } 2561 }
2562 catch 2562 catch
2563 { 2563 {
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index ecc2918..df980ab 100644
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ b/OpenSim/Region/Physics/Manager/IMesher.cs
@@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.Manager
37 { 37 {
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); 38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); 39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
40 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde); 40 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde);
41 IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex); 41 IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex);
42 void ReleaseMesh(IMesh mesh); 42 void ReleaseMesh(IMesh mesh);
43 void ExpireReleaseMeshs(); 43 void ExpireReleaseMeshs();
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 9338130..e2789d6 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -349,17 +349,20 @@ namespace OpenSim.Region.Physics.Manager
349 } 349 }
350 350
351 /// <summary> 351 /// <summary>
352 /// Velocity of this actor. 352 /// The desired velocity of this actor.
353 /// </summary> 353 /// </summary>
354 /// <remarks> 354 /// <remarks>
355 /// Setting this provides a target velocity for physics scene updates. 355 /// Setting this provides a target velocity for physics scene updates.
356 /// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity, 356 /// Getting this returns the last set target. Fetch Velocity to get the current velocity.
357 /// time to accelerate and collisions.
358 /// </remarks> 357 /// </remarks>
358 protected Vector3 m_targetVelocity;
359 public virtual Vector3 TargetVelocity 359 public virtual Vector3 TargetVelocity
360 { 360 {
361 get { return Velocity; } 361 get { return m_targetVelocity; }
362 set { Velocity = value; } 362 set {
363 m_targetVelocity = value;
364 Velocity = m_targetVelocity;
365 }
363 } 366 }
364 367
365 public abstract Vector3 Velocity { get; set; } 368 public abstract Vector3 Velocity { get; set; }
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
index 16846e6..80ecf66 100644
--- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs
+++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
@@ -64,16 +64,21 @@ namespace OpenSim.Region.Physics.Manager
64 { 64 {
65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
66 { 66 {
67 return CreateMesh(primName, primShape, size, lod, false); 67 return CreateMesh(primName, primShape, size, lod, false, false);
68 } 68 }
69 69
70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex,bool forOde) 70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex,bool forOde)
71 { 71 {
72 return CreateMesh(primName, primShape, size, lod, false); 72 return CreateMesh(primName, primShape, size, lod, false);
73 } 73 }
74 74
75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
76 { 76 {
77 return CreateMesh(primName, primShape, size, lod, false, false);
78 }
79
80 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
81 {
77 // Remove the reference to the encoded JPEG2000 data so it can be GCed 82 // Remove the reference to the encoded JPEG2000 data so it can be GCed
78 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; 83 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
79 84
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index f629c4d..d181b78 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
321 321
322 if (primShape.SculptData.Length <= 0) 322 if (primShape.SculptData.Length <= 0)
323 { 323 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
324// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); 327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
325 return false; 328 return false;
326 } 329 }
@@ -699,16 +702,21 @@ namespace OpenSim.Region.Physics.Meshing
699 702
700 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
701 { 704 {
702 return CreateMesh(primName, primShape, size, lod, false); 705 return CreateMesh(primName, primShape, size, lod, false, true);
703 } 706 }
704 707
705 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) 708 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
706 { 709 {
707 return CreateMesh(primName, primShape, size, lod, false); 710 return CreateMesh(primName, primShape, size, lod, false);
708 } 711 }
709 712
710 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 713 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
711 { 714 {
715 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
716 }
717
718 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
719 {
712#if SPAM 720#if SPAM
713 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); 721 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
714#endif 722#endif
@@ -718,9 +726,12 @@ namespace OpenSim.Region.Physics.Meshing
718 726
719 // If this mesh has been created already, return it instead of creating another copy 727 // If this mesh has been created already, return it instead of creating another copy
720 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory 728 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
721 key = primShape.GetMeshKey(size, lod); 729 if (shouldCache)
722 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 730 {
723 return mesh; 731 key = primShape.GetMeshKey(size, lod);
732 if (m_uniqueMeshes.TryGetValue(key, out mesh))
733 return mesh;
734 }
724 735
725 if (size.X < 0.01f) size.X = 0.01f; 736 if (size.X < 0.01f) size.X = 0.01f;
726 if (size.Y < 0.01f) size.Y = 0.01f; 737 if (size.Y < 0.01f) size.Y = 0.01f;
@@ -743,7 +754,10 @@ namespace OpenSim.Region.Physics.Meshing
743 // trim the vertex and triangle lists to free up memory 754 // trim the vertex and triangle lists to free up memory
744 mesh.TrimExcess(); 755 mesh.TrimExcess();
745 756
746 m_uniqueMeshes.Add(key, mesh); 757 if (shouldCache)
758 {
759 m_uniqueMeshes.Add(key, mesh);
760 }
747 } 761 }
748 762
749 return mesh; 763 return mesh;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a59f63f..d09aa62 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
3367 _pbs.SculptData = new byte[asset.Data.Length]; 3367 _pbs.SculptData = new byte[asset.Data.Length];
3368 asset.Data.CopyTo(_pbs.SculptData, 0); 3368 asset.Data.CopyTo(_pbs.SculptData, 0);
3369// m_assetFailed = false; 3369// m_assetFailed = false;
3370
3371// m_log.DebugFormat(
3372// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3373// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3374
3370 m_taintshape = true; 3375 m_taintshape = true;
3371 _parent_scene.AddPhysicsActorTaint(this); 3376 _parent_scene.AddPhysicsActorTaint(this);
3372 } 3377 }
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
index cbc6b95..16404c6 100644
--- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
+++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
@@ -32,13 +32,14 @@ using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin; 34using OpenSim.Region.Physics.OdePlugin;
35using OpenSim.Tests.Common;
35using log4net; 36using log4net;
36using System.Reflection; 37using System.Reflection;
37 38
38namespace OpenSim.Region.Physics.OdePlugin.Tests 39namespace OpenSim.Region.Physics.OdePlugin.Tests
39{ 40{
40 [TestFixture] 41 [TestFixture]
41 public class ODETestClass 42 public class ODETestClass : OpenSimTestCase
42 { 43 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 45
diff --git a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
index 6e1a105..00cbfbd 100644
--- a/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/UbitMeshing/Meshmerizer.cs
@@ -1031,12 +1031,12 @@ namespace OpenSim.Region.Physics.Meshing
1031 1031
1032 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 1032 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
1033 { 1033 {
1034 return CreateMesh(primName, primShape, size, lod, false,false,false); 1034 return CreateMesh(primName, primShape, size, lod, false,false,false,false);
1035 } 1035 }
1036 1036
1037 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 1037 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
1038 { 1038 {
1039 return CreateMesh(primName, primShape, size, lod, false,false,false); 1039 return CreateMesh(primName, primShape, size, lod, false,false,false,false);
1040 } 1040 }
1041 1041
1042 public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex) 1042 public IMesh GetMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex)
@@ -1080,7 +1080,7 @@ namespace OpenSim.Region.Physics.Meshing
1080 1080
1081 private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f); 1081 private static Vector3 m_MeshUnitSize = new Vector3(1.0f, 1.0f, 1.0f);
1082 1082
1083 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool convex, bool forOde) 1083 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache, bool convex, bool forOde)
1084 { 1084 {
1085#if SPAM 1085#if SPAM
1086 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); 1086 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
index 5030cec..0df71eb 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEMeshWorker.cs
@@ -448,7 +448,7 @@ namespace OpenSim.Region.Physics.OdePlugin
448 else 448 else
449 { 449 {
450 repData.meshState = MeshState.needMesh; 450 repData.meshState = MeshState.needMesh;
451 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); 451 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true);
452 if (mesh == null) 452 if (mesh == null)
453 { 453 {
454 repData.meshState = MeshState.MeshFailed; 454 repData.meshState = MeshState.MeshFailed;
@@ -513,7 +513,7 @@ namespace OpenSim.Region.Physics.OdePlugin
513 clod = (int)LevelOfDetail.Low; 513 clod = (int)LevelOfDetail.Low;
514 } 514 }
515 515
516 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true); 516 mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, false, convex, true);
517 517
518 if (mesh == null) 518 if (mesh == null)
519 { 519 {
@@ -929,4 +929,4 @@ namespace OpenSim.Region.Physics.OdePlugin
929 repData.actor.Name); 929 repData.actor.Name);
930 } 930 }
931 } 931 }
932} \ No newline at end of file 932}
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index b04f6b6..2f5b526 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -59,6 +59,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
59 public interface IScriptInstance 59 public interface IScriptInstance
60 { 60 {
61 /// <summary> 61 /// <summary>
62 /// Debug level for this script instance.
63 /// </summary>
64 /// <remarks>
65 /// Level == 0, no extra data is logged.
66 /// Level >= 1, state changes are logged.
67 /// Level >= 2, event firing is logged.
68 /// <value>
69 /// The debug level.
70 /// </value>
71 int DebugLevel { get; set; }
72
73 /// <summary>
62 /// Is the script currently running? 74 /// Is the script currently running?
63 /// </summary> 75 /// </summary>
64 bool Running { get; set; } 76 bool Running { get; set; }
@@ -114,6 +126,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
114 UUID AssetID { get; } 126 UUID AssetID { get; }
115 Queue EventQueue { get; } 127 Queue EventQueue { get; }
116 128
129 /// <summary>
130 /// Number of events queued for processing.
131 /// </summary>
132 long EventsQueued { get; }
133
134 /// <summary>
135 /// Number of events processed by this script instance.
136 /// </summary>
137 long EventsProcessed { get; }
138
117 void ClearQueue(); 139 void ClearQueue();
118 int StartParam { get; set; } 140 int StartParam { get; set; }
119 141
@@ -125,7 +147,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
125 /// <summary> 147 /// <summary>
126 /// Stop the script instance. 148 /// Stop the script instance.
127 /// </summary> 149 /// </summary>
150 /// <remarks>
151 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
152 /// there is a danger that it will self-abort and not complete the reset.
153 /// </remarks>
128 /// <param name="timeout"></param> 154 /// <param name="timeout"></param>
155 /// How many milliseconds we will wait for an existing script event to finish before
156 /// forcibly aborting that event.
129 /// <returns>true if the script was successfully stopped, false otherwise</returns> 157 /// <returns>true if the script was successfully stopped, false otherwise</returns>
130 bool Stop(int timeout); 158 bool Stop(int timeout);
131 159
@@ -147,8 +175,31 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
147 object EventProcessor(); 175 object EventProcessor();
148 176
149 int EventTime(); 177 int EventTime();
150 void ResetScript(); 178
179 /// <summary>
180 /// Reset the script.
181 /// </summary>
182 /// <remarks>
183 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
184 /// there is a danger that it will self-abort and not complete the reset. Such a thread must call
185 /// ApiResetScript() instead.
186 /// </remarks>
187 /// <param name='timeout'>
188 /// How many milliseconds we will wait for an existing script event to finish before
189 /// forcibly aborting that event prior to script reset.
190 /// </param>
191 void ResetScript(int timeout);
192
193 /// <summary>
194 /// Reset the script.
195 /// </summary>
196 /// <remarks>
197 /// This must not be called by any thread other than the one executing the scripts current event. This is
198 /// because there is no wait or abort logic if another thread is in the middle of processing a script event.
199 /// Such an external thread should use ResetScript() instead.
200 /// </remarks>
151 void ApiResetScript(); 201 void ApiResetScript();
202
152 Dictionary<string, object> GetVars(); 203 Dictionary<string, object> GetVars();
153 void SetVars(Dictionary<string, object> vars); 204 void SetVars(Dictionary<string, object> vars);
154 DetectParams GetDetectParams(int idx); 205 DetectParams GetDetectParams(int idx);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 7ff30ca..3a9d0ff 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -7334,6 +7334,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7334 public void llCloseRemoteDataChannel(string channel) 7334 public void llCloseRemoteDataChannel(string channel)
7335 { 7335 {
7336 m_host.AddScriptLPS(1); 7336 m_host.AddScriptLPS(1);
7337
7338 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
7339 if (xmlRpcRouter != null)
7340 {
7341 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
7342 }
7343
7337 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 7344 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7338 xmlrpcMod.CloseXMLRPCChannel((UUID)channel); 7345 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
7339 ScriptSleep(1000); 7346 ScriptSleep(1000);
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs
index 7763619..77e087c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs
@@ -39,7 +39,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests
39 /// The generated C# code is compared against the expected C# code. 39 /// The generated C# code is compared against the expected C# code.
40 /// </summary> 40 /// </summary>
41 [TestFixture] 41 [TestFixture]
42 public class CSCodeGeneratorTest 42 public class CSCodeGeneratorTest : OpenSimTestCase
43 { 43 {
44 [Test] 44 [Test]
45 public void TestDefaultState() 45 public void TestDefaultState()
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs
index 1fa6954..05a8756 100644
--- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs
@@ -41,7 +41,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests
41 /// the LSL source. 41 /// the LSL source.
42 /// </summary> 42 /// </summary>
43 [TestFixture] 43 [TestFixture]
44 public class CompilerTest 44 public class CompilerTest : OpenSimTestCase
45 { 45 {
46 private string m_testDir; 46 private string m_testDir;
47 private CSharpCodeProvider m_CSCodeProvider; 47 private CSharpCodeProvider m_CSCodeProvider;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 771db0c..ff4d130 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -94,6 +94,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
94 private UUID m_CurrentStateHash; 94 private UUID m_CurrentStateHash;
95 private UUID m_RegionID; 95 private UUID m_RegionID;
96 96
97 public int DebugLevel { get; set; }
98
97 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; } 99 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap { get; set; }
98 100
99 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>(); 101 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
@@ -174,6 +176,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
174 176
175 public Queue EventQueue { get; private set; } 177 public Queue EventQueue { get; private set; }
176 178
179 public long EventsQueued
180 {
181 get
182 {
183 lock (EventQueue)
184 return EventQueue.Count;
185 }
186 }
187
188 public long EventsProcessed { get; private set; }
189
177 public int StartParam { get; set; } 190 public int StartParam { get; set; }
178 191
179 public TaskInventoryItem ScriptTask { get; private set; } 192 public TaskInventoryItem ScriptTask { get; private set; }
@@ -538,9 +551,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
538 // forcibly abort the work item (this aborts the underlying thread). 551 // forcibly abort the work item (this aborts the underlying thread).
539 if (!m_InSelfDelete) 552 if (!m_InSelfDelete)
540 { 553 {
541// m_log.ErrorFormat( 554 m_log.DebugFormat(
542// "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", 555 "[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms",
543// ScriptName, ItemID, PrimName, ObjectID, m_InSelfDelete, DateTime.Now.Ticks); 556 ScriptName, ItemID, PrimName, LocalID, timeout);
544 557
545 workItem.Abort(); 558 workItem.Abort();
546 } 559 }
@@ -696,19 +709,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
696 { 709 {
697 710
698// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); 711// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
712 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
713
714 if (DebugLevel >= 2)
715 m_log.DebugFormat(
716 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
717 data.EventName,
718 ScriptName,
719 part.Name,
720 part.LocalId,
721 part.ParentGroup.Name,
722 part.ParentGroup.UUID,
723 part.AbsolutePosition,
724 part.ParentGroup.Scene.Name);
699 725
700 m_DetectParams = data.DetectParams; 726 m_DetectParams = data.DetectParams;
701 727
702 if (data.EventName == "state") // Hardcoded state change 728 if (data.EventName == "state") // Hardcoded state change
703 { 729 {
704 // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}",
705 // PrimName, ScriptName, data.Params[0].ToString());
706 State = data.Params[0].ToString(); 730 State = data.Params[0].ToString();
731
732 if (DebugLevel >= 1)
733 m_log.DebugFormat(
734 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
735 State,
736 ScriptName,
737 part.Name,
738 part.LocalId,
739 part.ParentGroup.Name,
740 part.ParentGroup.UUID,
741 part.AbsolutePosition,
742 part.ParentGroup.Scene.Name);
743
707 AsyncCommandManager.RemoveScript(Engine, 744 AsyncCommandManager.RemoveScript(Engine,
708 LocalID, ItemID); 745 LocalID, ItemID);
709 746
710 SceneObjectPart part = Engine.World.GetSceneObjectPart(
711 LocalID);
712 if (part != null) 747 if (part != null)
713 { 748 {
714 part.SetScriptEvents(ItemID, 749 part.SetScriptEvents(ItemID,
@@ -720,8 +755,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
720 if (Engine.World.PipeEventsForScript(LocalID) || 755 if (Engine.World.PipeEventsForScript(LocalID) ||
721 data.EventName == "control") // Don't freeze avies! 756 data.EventName == "control") // Don't freeze avies!
722 { 757 {
723 SceneObjectPart part = Engine.World.GetSceneObjectPart(
724 LocalID);
725 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", 758 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
726 // PrimName, ScriptName, data.EventName, State); 759 // PrimName, ScriptName, data.EventName, State);
727 760
@@ -776,6 +809,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
776 ChatTypeEnum.DebugChannel, 2147483647, 809 ChatTypeEnum.DebugChannel, 2147483647,
777 part.AbsolutePosition, 810 part.AbsolutePosition,
778 part.Name, part.UUID, false); 811 part.Name, part.UUID, false);
812
813
814 m_log.DebugFormat(
815 "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
816 ScriptName,
817 PrimName,
818 part.UUID,
819 part.AbsolutePosition,
820 part.ParentGroup.Scene.Name,
821 text.Replace("\n", "\\n"),
822 e.InnerException);
779 } 823 }
780 catch (Exception) 824 catch (Exception)
781 { 825 {
@@ -810,6 +854,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
810 // script engine to run the next event. 854 // script engine to run the next event.
811 lock (EventQueue) 855 lock (EventQueue)
812 { 856 {
857 EventsProcessed++;
858
813 if (EventQueue.Count > 0 && Running && !ShuttingDown) 859 if (EventQueue.Count > 0 && Running && !ShuttingDown)
814 { 860 {
815 m_CurrentWorkItem = Engine.QueueEventHandler(this); 861 m_CurrentWorkItem = Engine.QueueEventHandler(this);
@@ -834,7 +880,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
834 return (DateTime.Now - m_EventStart).Seconds; 880 return (DateTime.Now - m_EventStart).Seconds;
835 } 881 }
836 882
837 public void ResetScript() 883 public void ResetScript(int timeout)
838 { 884 {
839 if (m_Script == null) 885 if (m_Script == null)
840 return; 886 return;
@@ -844,7 +890,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
844 RemoveState(); 890 RemoveState();
845 ReleaseControls(); 891 ReleaseControls();
846 892
847 Stop(0); 893 Stop(timeout);
848 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 894 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
849 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; 895 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
850 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; 896 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
@@ -1015,7 +1061,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1015 "({0}): {1}", scriptLine - 1, 1061 "({0}): {1}", scriptLine - 1,
1016 e.InnerException.Message); 1062 e.InnerException.Message);
1017 1063
1018 System.Console.WriteLine(e.ToString()+"\n");
1019 return message; 1064 return message;
1020 } 1065 }
1021 } 1066 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
index c73e22f..cb7291a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
@@ -51,14 +51,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
51 /// Tests for inventory functions in LSL 51 /// Tests for inventory functions in LSL
52 /// </summary> 52 /// </summary>
53 [TestFixture] 53 [TestFixture]
54 public class LSL_ApiInventoryTests 54 public class LSL_ApiInventoryTests : OpenSimTestCase
55 { 55 {
56 protected Scene m_scene; 56 protected Scene m_scene;
57 protected XEngine.XEngine m_engine; 57 protected XEngine.XEngine m_engine;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 IConfigSource initConfigSource = new IniConfigSource(); 64 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 65 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 66 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
index 2565ae7..d9b17d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
@@ -56,14 +56,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
56 /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. 56 /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests.
57 /// </remarks> 57 /// </remarks>
58 [TestFixture] 58 [TestFixture]
59 public class LSL_ApiLinkingTests 59 public class LSL_ApiLinkingTests : OpenSimTestCase
60 { 60 {
61 protected Scene m_scene; 61 protected Scene m_scene;
62 protected XEngine.XEngine m_engine; 62 protected XEngine.XEngine m_engine;
63 63
64 [SetUp] 64 [SetUp]
65 public void SetUp() 65 public override void SetUp()
66 { 66 {
67 base.SetUp();
68
67 IConfigSource initConfigSource = new IniConfigSource(); 69 IConfigSource initConfigSource = new IniConfigSource();
68 IConfig config = initConfigSource.AddConfig("XEngine"); 70 IConfig config = initConfigSource.AddConfig("XEngine");
69 config.Set("Enabled", "true"); 71 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
index dd23be8..98017d8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
@@ -46,13 +46,15 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
46namespace OpenSim.Region.ScriptEngine.Shared.Tests 46namespace OpenSim.Region.ScriptEngine.Shared.Tests
47{ 47{
48 [TestFixture] 48 [TestFixture]
49 public class LSL_ApiListTests 49 public class LSL_ApiListTests : OpenSimTestCase
50 { 50 {
51 private LSL_Api m_lslApi; 51 private LSL_Api m_lslApi;
52 52
53 [SetUp] 53 [SetUp]
54 public void SetUp() 54 public override void SetUp()
55 { 55 {
56 base.SetUp();
57
56 IConfigSource initConfigSource = new IniConfigSource(); 58 IConfigSource initConfigSource = new IniConfigSource();
57 IConfig config = initConfigSource.AddConfig("XEngine"); 59 IConfig config = initConfigSource.AddConfig("XEngine");
58 config.Set("Enabled", "true"); 60 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs
index 3ed2562..c8c7f82 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLFloat.cs
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared;
33namespace OpenSim.Region.ScriptEngine.Shared.Tests 33namespace OpenSim.Region.ScriptEngine.Shared.Tests
34{ 34{
35 [TestFixture] 35 [TestFixture]
36 public class LSL_TypesTestLSLFloat 36 public class LSL_TypesTestLSLFloat : OpenSimTestCase
37 { 37 {
38 // Used for testing equality of two floats. 38 // Used for testing equality of two floats.
39 private double _lowPrecisionTolerance = 0.000001; 39 private double _lowPrecisionTolerance = 0.000001;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs
index 8d1169a..c664108 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLInteger.cs
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared;
33namespace OpenSim.Region.ScriptEngine.Shared.Tests 33namespace OpenSim.Region.ScriptEngine.Shared.Tests
34{ 34{
35 [TestFixture] 35 [TestFixture]
36 public class LSL_TypesTestLSLInteger 36 public class LSL_TypesTestLSLInteger : OpenSimTestCase
37 { 37 {
38 private Dictionary<double, int> m_doubleIntSet; 38 private Dictionary<double, int> m_doubleIntSet;
39 private Dictionary<string, int> m_stringIntSet; 39 private Dictionary<string, int> m_stringIntSet;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs
index c4ca1a8..8550f2d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestLSLString.cs
@@ -33,7 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared;
33namespace OpenSim.Region.ScriptEngine.Shared.Tests 33namespace OpenSim.Region.ScriptEngine.Shared.Tests
34{ 34{
35 [TestFixture] 35 [TestFixture]
36 public class LSL_TypesTestLSLString 36 public class LSL_TypesTestLSLString : OpenSimTestCase
37 { 37 {
38 private Dictionary<double, string> m_doubleStringSet; 38 private Dictionary<double, string> m_doubleStringSet;
39 39
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs
index b81225f..71b88bc 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestList.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
36 /// Tests the LSL_Types.list class. 36 /// Tests the LSL_Types.list class.
37 /// </summary> 37 /// </summary>
38 [TestFixture] 38 [TestFixture]
39 public class LSL_TypesTestList 39 public class LSL_TypesTestList : OpenSimTestCase
40 { 40 {
41 /// <summary> 41 /// <summary>
42 /// Tests concatenating a string to a list. 42 /// Tests concatenating a string to a list.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs
index ebf8001..0c838af 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_TypesTestVector3.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
36 /// Tests for Vector3 36 /// Tests for Vector3
37 /// </summary> 37 /// </summary>
38 [TestFixture] 38 [TestFixture]
39 public class LSL_TypesTestVector3 39 public class LSL_TypesTestVector3 : OpenSimTestCase
40 { 40 {
41 [Test] 41 [Test]
42 public void TestDotProduct() 42 public void TestDotProduct()
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
index c401794..1381d2b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
@@ -51,14 +51,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
51 /// Tests for OSSL_Api 51 /// Tests for OSSL_Api
52 /// </summary> 52 /// </summary>
53 [TestFixture] 53 [TestFixture]
54 public class OSSL_ApiAppearanceTest 54 public class OSSL_ApiAppearanceTest : OpenSimTestCase
55 { 55 {
56 protected Scene m_scene; 56 protected Scene m_scene;
57 protected XEngine.XEngine m_engine; 57 protected XEngine.XEngine m_engine;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 IConfigSource initConfigSource = new IniConfigSource(); 64 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 65 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 66 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
index b49bcc2..d6c82f1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
@@ -127,12 +127,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
127 OSSL_Api osslApi = new OSSL_Api(); 127 OSSL_Api osslApi = new OSSL_Api();
128 osslApi.Initialize(m_engine, so.RootPart, null); 128 osslApi.Initialize(m_engine, so.RootPart, null);
129 129
130 string npcRaw;
131 bool gotExpectedException = false; 130 bool gotExpectedException = false;
132 try 131 try
133 { 132 {
134 npcRaw 133 osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
135 = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
136 } 134 }
137 catch (ScriptException) 135 catch (ScriptException)
138 { 136 {
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
index f331658..5abfe9a 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests
44 /// XEngine tests. 44 /// XEngine tests.
45 /// </summary> 45 /// </summary>
46 [TestFixture] 46 [TestFixture]
47 public class XEngineTest 47 public class XEngineTest : OpenSimTestCase
48 { 48 {
49 private TestScene m_scene; 49 private TestScene m_scene;
50 private XEngine m_xEngine; 50 private XEngine m_xEngine;
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 9f05666..0bd9a06 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.Diagnostics; //for [DebuggerNonUserCode] 31using System.Diagnostics; //for [DebuggerNonUserCode]
32using System.Globalization; 32using System.Globalization;
33using System.IO; 33using System.IO;
34using System.Linq;
34using System.Reflection; 35using System.Reflection;
35using System.Security; 36using System.Security;
36using System.Security.Policy; 37using System.Security.Policy;
@@ -107,6 +108,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
107 private IXmlRpcRouter m_XmlRpcRouter; 108 private IXmlRpcRouter m_XmlRpcRouter;
108 private int m_EventLimit; 109 private int m_EventLimit;
109 private bool m_KillTimedOutScripts; 110 private bool m_KillTimedOutScripts;
111
112 /// <summary>
113 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
114 /// its thread.
115 /// </summary>
116 /// <remarks>
117 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
118 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
119 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
120 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
121 /// actually hold.
122 ///
123 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
124 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
125 /// shutting down.
126 /// </remarks>
127 private int m_WaitForEventCompletionOnScriptStop = 1000;
128
110 private string m_ScriptEnginesPath = null; 129 private string m_ScriptEnginesPath = null;
111 130
112 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>(); 131 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
@@ -316,6 +335,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
316 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 335 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
317 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 336 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
318 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; 337 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
338 m_WaitForEventCompletionOnScriptStop
339 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
340
319 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); 341 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
320 342
321 m_Prio = ThreadPriority.BelowNormal; 343 m_Prio = ThreadPriority.BelowNormal;
@@ -371,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
371 393
372 MainConsole.Instance.Commands.AddCommand( 394 MainConsole.Instance.Commands.AddCommand(
373 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", 395 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information",
374 "Show information on all scripts known to the script engine." 396 "Show information on all scripts known to the script engine.\n"
375 + "If a <script-item-uuid> is given then only information on that script will be shown.", 397 + "If a <script-item-uuid> is given then only information on that script will be shown.",
376 HandleShowScripts); 398 HandleShowScripts);
377 399
@@ -390,22 +412,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine
390 MainConsole.Instance.Commands.AddCommand( 412 MainConsole.Instance.Commands.AddCommand(
391 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", 413 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts",
392 "Resumes all currently suspended scripts.\n" 414 "Resumes all currently suspended scripts.\n"
393 + "Resumed scripts will process all events accumulated whilst suspended." 415 + "Resumed scripts will process all events accumulated whilst suspended.\n"
394 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.", 416 + "If a <script-item-uuid> is given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
395 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); 417 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
396 418
397 MainConsole.Instance.Commands.AddCommand( 419 MainConsole.Instance.Commands.AddCommand(
398 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", 420 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts",
399 "Stops all running scripts." 421 "Stops all running scripts.\n"
400 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.", 422 + "If a <script-item-uuid> is given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
401 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); 423 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
402 424
403 MainConsole.Instance.Commands.AddCommand( 425 MainConsole.Instance.Commands.AddCommand(
404 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", 426 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts",
405 "Starts all stopped scripts." 427 "Starts all stopped scripts.\n"
406 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", 428 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
407 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); 429 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
408 430
431 MainConsole.Instance.Commands.AddCommand(
432 "Scripts", false, "debug script log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
433 "Activates or deactivates extra debug logging for the given script.\n"
434 + "Level == 0, deactivate extra debug logging.\n"
435 + "Level >= 1, log state changes.\n"
436 + "Level >= 2, log event invocations.\n",
437 HandleDebugScriptLogCommand);
438
409// MainConsole.Instance.Commands.AddCommand( 439// MainConsole.Instance.Commands.AddCommand(
410// "Debug", false, "debug xengine", "debug xengine [<level>]", 440// "Debug", false, "debug xengine", "debug xengine [<level>]",
411// "Turn on detailed xengine debugging.", 441// "Turn on detailed xengine debugging.",
@@ -414,6 +444,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
414// HandleDebugLevelCommand); 444// HandleDebugLevelCommand);
415 } 445 }
416 446
447 private void HandleDebugScriptLogCommand(string module, string[] args)
448 {
449 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
450 return;
451
452 if (args.Length != 5)
453 {
454 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
455 return;
456 }
457
458 UUID itemId;
459
460 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
461 return;
462
463 int newLevel;
464
465 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
466 return;
467
468 IScriptInstance si;
469
470 lock (m_Scripts)
471 {
472 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
473 // engine
474 if (!m_Scripts.TryGetValue(itemId, out si))
475 return;
476 }
477
478 si.DebugLevel = newLevel;
479 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
480 }
481
417 /// <summary> 482 /// <summary>
418 /// Change debug level 483 /// Change debug level
419 /// </summary> 484 /// </summary>
@@ -445,9 +510,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
445 /// </summary> 510 /// </summary>
446 /// <param name="cmdparams"></param> 511 /// <param name="cmdparams"></param>
447 /// <param name="instance"></param> 512 /// <param name="instance"></param>
448 /// <returns>true if we're okay to proceed, false if not.</returns> 513 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
449 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) 514 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
450 { 515 {
516 HandleScriptsAction<object>(cmdparams, action, null);
517 }
518
519 /// <summary>
520 /// Parse the raw item id into a script instance from the command params if it's present.
521 /// </summary>
522 /// <param name="cmdparams"></param>
523 /// <param name="instance"></param>
524 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
525 private void HandleScriptsAction<TKey>(
526 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
527 {
451 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 528 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
452 return; 529 return;
453 530
@@ -458,7 +535,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
458 535
459 if (cmdparams.Length == 2) 536 if (cmdparams.Length == 2)
460 { 537 {
461 foreach (IScriptInstance instance in m_Scripts.Values) 538 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
539
540 if (keySelector != null)
541 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
542
543 foreach (IScriptInstance instance in scripts)
462 action(instance); 544 action(instance);
463 545
464 return; 546 return;
@@ -468,7 +550,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
468 550
469 if (!UUID.TryParse(rawItemId, out itemId)) 551 if (!UUID.TryParse(rawItemId, out itemId))
470 { 552 {
471 MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId); 553 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
472 return; 554 return;
473 } 555 }
474 556
@@ -505,9 +587,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
505 StringBuilder sb = new StringBuilder(); 587 StringBuilder sb = new StringBuilder();
506 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); 588 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
507 589
590 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
591
508 lock (m_Scripts) 592 lock (m_Scripts)
509 sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); 593 {
594 scriptsLoaded = m_Scripts.Count;
595
596 foreach (IScriptInstance si in m_Scripts.Values)
597 {
598 eventsQueued += si.EventsQueued;
599 eventsProcessed += si.EventsProcessed;
600 }
601 }
510 602
603 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
511 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); 604 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
512 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); 605 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
513 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); 606 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@@ -516,6 +609,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
516 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); 609 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
517 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); 610 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
518// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); 611// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
612 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
613 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
519 614
520 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); 615 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
521 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); 616 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@@ -546,7 +641,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
546 } 641 }
547 } 642 }
548 643
549 HandleScriptsAction(cmdparams, HandleShowScript); 644 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
550 } 645 }
551 646
552 private void HandleShowScript(IScriptInstance instance) 647 private void HandleShowScript(IScriptInstance instance)
@@ -576,11 +671,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
576 671
577 sb.AppendFormat("Script name : {0}\n", instance.ScriptName); 672 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
578 sb.AppendFormat("Status : {0}\n", status); 673 sb.AppendFormat("Status : {0}\n", status);
579 674 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
580 lock (eq) 675 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
581 sb.AppendFormat("Queued events : {0}\n", eq.Count);
582
583 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); 676 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
677 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
584 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 678 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
585 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 679 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
586 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 680 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@@ -1089,8 +1183,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 1183
1090 string assembly = ""; 1184 string assembly = "";
1091 1185
1092 CultureInfo USCulture = new CultureInfo("en-US"); 1186 Culture.SetCurrentCulture();
1093 Thread.CurrentThread.CurrentCulture = USCulture;
1094 1187
1095 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; 1188 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1096 1189
@@ -1347,9 +1440,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1347 lockScriptsForWrite(false); 1440 lockScriptsForWrite(false);
1348 instance.ClearQueue(); 1441 instance.ClearQueue();
1349 1442
1350 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1443 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1351 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1352 instance.Stop(1000);
1353 1444
1354// bool objectRemoved = false; 1445// bool objectRemoved = false;
1355 1446
@@ -1504,8 +1595,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1504 /// <returns></returns> 1595 /// <returns></returns>
1505 private object ProcessEventHandler(object parms) 1596 private object ProcessEventHandler(object parms)
1506 { 1597 {
1507 CultureInfo USCulture = new CultureInfo("en-US"); 1598 Culture.SetCurrentCulture();
1508 Thread.CurrentThread.CurrentCulture = USCulture;
1509 1599
1510 IScriptInstance instance = (ScriptInstance) parms; 1600 IScriptInstance instance = (ScriptInstance) parms;
1511 1601
@@ -1693,7 +1783,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1693 { 1783 {
1694 IScriptInstance instance = GetInstance(itemID); 1784 IScriptInstance instance = GetInstance(itemID);
1695 if (instance != null) 1785 if (instance != null)
1696 instance.ResetScript(); 1786 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1697 } 1787 }
1698 1788
1699 public void StartScript(UUID itemID) 1789 public void StartScript(UUID itemID)
@@ -1708,16 +1798,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1708 public void StopScript(UUID itemID) 1798 public void StopScript(UUID itemID)
1709 { 1799 {
1710 IScriptInstance instance = GetInstance(itemID); 1800 IScriptInstance instance = GetInstance(itemID);
1801
1711 if (instance != null) 1802 if (instance != null)
1712 { 1803 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1713 // Give the script some time to finish processing its last event. Simply aborting the script thread can
1714 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1715 instance.Stop(1000);
1716 }
1717 else 1804 else
1718 {
1719 m_runFlags.AddOrUpdate(itemID, false, 240); 1805 m_runFlags.AddOrUpdate(itemID, false, 240);
1720 }
1721 } 1806 }
1722 1807
1723 public DetectParams GetDetectParams(UUID itemID, int idx) 1808 public DetectParams GetDetectParams(UUID itemID, int idx)
diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs
index b08233c..64cb577 100644
--- a/OpenSim/Region/UserStatistics/WebStatsModule.cs
+++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs
@@ -94,8 +94,6 @@ namespace OpenSim.Region.UserStatistics
94 if (!enabled) 94 if (!enabled)
95 return; 95 return;
96 96
97 AddEventHandlers();
98
99 if (Util.IsWindows()) 97 if (Util.IsWindows())
100 Util.LoadArchSpecificWindowsDll("sqlite3.dll"); 98 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
101 99
@@ -143,10 +141,14 @@ namespace OpenSim.Region.UserStatistics
143 lock (m_scenes) 141 lock (m_scenes)
144 { 142 {
145 m_scenes.Add(scene); 143 m_scenes.Add(scene);
146 if (m_simstatsCounters.ContainsKey(scene.RegionInfo.RegionID)) 144 updateLogMod = m_scenes.Count * 2;
147 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
148 145
149 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); 146 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
147
148 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
149 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
150 scene.EventManager.OnClientClosed += OnClientClosed;
151 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
150 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; 152 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
151 } 153 }
152 } 154 }
@@ -157,6 +159,15 @@ namespace OpenSim.Region.UserStatistics
157 159
158 public void RemoveRegion(Scene scene) 160 public void RemoveRegion(Scene scene)
159 { 161 {
162 if (!enabled)
163 return;
164
165 lock (m_scenes)
166 {
167 m_scenes.Remove(scene);
168 updateLogMod = m_scenes.Count * 2;
169 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
170 }
160 } 171 }
161 172
162 public virtual void Close() 173 public virtual void Close()
@@ -187,9 +198,7 @@ namespace OpenSim.Region.UserStatistics
187 private void ReceiveClassicSimStatsPacket(SimStats stats) 198 private void ReceiveClassicSimStatsPacket(SimStats stats)
188 { 199 {
189 if (!enabled) 200 if (!enabled)
190 {
191 return; 201 return;
192 }
193 202
194 try 203 try
195 { 204 {
@@ -198,17 +207,25 @@ namespace OpenSim.Region.UserStatistics
198 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) 207 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
199 return; 208 return;
200 209
201 if ((updateLogCounter++ % updateLogMod) == 0) 210 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
211 // confused if a scene is removed.
212 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
213 lock (m_scenes)
202 { 214 {
203 m_loglines = readLogLines(10); 215 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
204 if (updateLogCounter > 10000) updateLogCounter = 1; 216 {
205 } 217 m_loglines = readLogLines(10);
206 218
207 USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; 219 if (updateLogCounter > 10000)
220 updateLogCounter = 1;
221 }
208 222
209 if ((++ss.StatsCounter % updateStatsMod) == 0) 223 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
210 { 224
211 ss.ConsumeSimStats(stats); 225 if ((++ss.StatsCounter % updateStatsMod) == 0)
226 {
227 ss.ConsumeSimStats(stats);
228 }
212 } 229 }
213 } 230 }
214 catch (KeyNotFoundException) 231 catch (KeyNotFoundException)
diff --git a/OpenSim/Server/Base/CommandManager.cs b/OpenSim/Server/Base/CommandManager.cs
new file mode 100644
index 0000000..bd18485
--- /dev/null
+++ b/OpenSim/Server/Base/CommandManager.cs
@@ -0,0 +1,359 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29using System;
30using System.Text;
31using System.Linq;
32using System.Collections;
33using System.Collections.Generic;
34using System.Collections.ObjectModel;
35using Mono.Addins.Setup;
36using Mono.Addins;
37using Mono.Addins.Description;
38using OpenSim.Framework;
39
40namespace OpenSim.Server.Base
41{
42 /// <summary>
43 /// Command manager -
44 /// Wrapper for OpenSim.Framework.PluginManager to allow
45 /// us to add commands to the console to perform operations
46 /// on our repos and plugins
47 /// </summary>
48 public class CommandManager
49 {
50 public AddinRegistry PluginRegistry;
51 protected PluginManager PluginManager;
52
53 public CommandManager(AddinRegistry registry)
54 {
55 PluginRegistry = registry;
56 PluginManager = new PluginManager(PluginRegistry);
57 AddManagementCommands();
58 }
59
60 private void AddManagementCommands()
61 {
62 // add plugin
63 MainConsole.Instance.Commands.AddCommand("Plugin", true,
64 "plugin add", "plugin add \"plugin index\"",
65 "Install plugin from repository.",
66 HandleConsoleInstallPlugin);
67
68 // remove plugin
69 MainConsole.Instance.Commands.AddCommand("Plugin", true,
70 "plugin remove", "plugin remove \"plugin index\"",
71 "Remove plugin from repository",
72 HandleConsoleUnInstallPlugin);
73
74 // list installed plugins
75 MainConsole.Instance.Commands.AddCommand("Plugin", true,
76 "plugin list installed",
77 "plugin list installed","List install plugins",
78 HandleConsoleListInstalledPlugin);
79
80 // list plugins available from registered repositories
81 MainConsole.Instance.Commands.AddCommand("Plugin", true,
82 "plugin list available",
83 "plugin list available","List available plugins",
84 HandleConsoleListAvailablePlugin);
85 // List available updates
86 MainConsole.Instance.Commands.AddCommand("Plugin", true,
87 "plugin updates", "plugin updates","List availble updates",
88 HandleConsoleListUpdates);
89
90 // Update plugin
91 MainConsole.Instance.Commands.AddCommand("Plugin", true,
92 "plugin update", "plugin update \"plugin index\"","Update the plugin",
93 HandleConsoleUpdatePlugin);
94
95 // Add repository
96 MainConsole.Instance.Commands.AddCommand("Repository", true,
97 "repo add", "repo add \"url\"","Add repository",
98 HandleConsoleAddRepo);
99
100 // Refresh repo
101 MainConsole.Instance.Commands.AddCommand("Repository", true,
102 "repo refresh", "repo refresh \"url\"", "Sync with a registered repository",
103 HandleConsoleGetRepo);
104
105 // Remove repository from registry
106 MainConsole.Instance.Commands.AddCommand("Repository", true,
107 "repo remove",
108 "repo remove \"[url | index]\"",
109 "Remove repository from registry",
110 HandleConsoleRemoveRepo);
111
112 // Enable repo
113 MainConsole.Instance.Commands.AddCommand("Repository", true,
114 "repo enable", "repo enable \"[url | index]\"",
115 "Enable registered repository",
116 HandleConsoleEnableRepo);
117
118 // Disable repo
119 MainConsole.Instance.Commands.AddCommand("Repository", true,
120 "repo disable", "repo disable\"[url | index]\"",
121 "Disable registered repository",
122 HandleConsoleDisableRepo);
123
124 // List registered repositories
125 MainConsole.Instance.Commands.AddCommand("Repository", true,
126 "repo list", "repo list",
127 "List registered repositories",
128 HandleConsoleListRepos);
129
130 // *
131 MainConsole.Instance.Commands.AddCommand("Plugin", true,
132 "plugin info", "plugin info \"plugin index\"","Show detailed information for plugin",
133 HandleConsoleShowAddinInfo);
134
135 // Plugin disable
136 MainConsole.Instance.Commands.AddCommand("Plugin", true,
137 "plugin disable", "plugin disable \"plugin index\"",
138 "Disable a plugin",
139 HandleConsoleDisablePlugin);
140
141 // Enable plugin
142 MainConsole.Instance.Commands.AddCommand("Plugin", true,
143 "plugin enable", "plugin enable \"plugin index\"",
144 "Enable the selected plugin plugin",
145 HandleConsoleEnablePlugin);
146 }
147
148 #region console handlers
149 // Handle our console commands
150 //
151 // Install plugin from registered repository
152 /// <summary>
153 /// Handles the console install plugin command. Attempts to install the selected plugin
154 /// and
155 /// </summary>
156 /// <param name='module'>
157 /// Module.
158 /// </param>
159 /// <param name='cmd'>
160 /// Cmd.
161 /// </param>
162 private void HandleConsoleInstallPlugin(string module, string[] cmd)
163 {
164 Dictionary<string, object> result = new Dictionary<string, object>();
165
166 if (cmd.Length == 3)
167 {
168 int ndx = Convert.ToInt16(cmd[2]);
169 if (PluginManager.InstallPlugin(ndx, out result) == true)
170 {
171 ArrayList s = new ArrayList();
172 s.AddRange(result.Keys);
173 s.Sort();
174
175 var list = result.Keys.ToList();
176 list.Sort();
177 foreach (var k in list)
178 {
179 Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
180 bool enabled = (bool)plugin["enabled"];
181 MainConsole.Instance.OutputFormat("{0}) {1} {2} rev. {3}",
182 k,
183 enabled == true ? "[ ]" : "[X]",
184 plugin["name"], plugin["version"]);
185 }
186 }
187 }
188 return;
189 }
190
191 // Remove installed plugin
192 private void HandleConsoleUnInstallPlugin(string module, string[] cmd)
193 {
194 if (cmd.Length == 3)
195 {
196 int ndx = Convert.ToInt16(cmd[2]);
197 PluginManager.UnInstall(ndx);
198 }
199 return;
200 }
201
202 // List installed plugins
203 private void HandleConsoleListInstalledPlugin(string module, string[] cmd)
204 {
205 Dictionary<string, object> result = new Dictionary<string, object>();
206 PluginManager.ListInstalledAddins(out result);
207
208 ArrayList s = new ArrayList();
209 s.AddRange(result.Keys);
210 s.Sort();
211
212 var list = result.Keys.ToList();
213 list.Sort();
214 foreach (var k in list)
215 {
216 Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
217 bool enabled = (bool)plugin["enabled"];
218 MainConsole.Instance.OutputFormat("{0}) {1} {2} rev. {3}",
219 k,
220 enabled == true ? "[ ]" : "[X]",
221 plugin["name"], plugin["version"]);
222 }
223 return;
224 }
225
226 // List available plugins on registered repositories
227 private void HandleConsoleListAvailablePlugin(string module, string[] cmd)
228 {
229 Dictionary<string, object> result = new Dictionary<string, object>();
230 PluginManager.ListAvailable(out result);
231
232 var list = result.Keys.ToList();
233 list.Sort();
234 foreach (var k in list)
235 {
236 // name, version, repository
237 Dictionary<string, object> plugin = (Dictionary<string, object>)result[k];
238 MainConsole.Instance.OutputFormat("{0}) {1} rev. {2} {3}",
239 k,
240 plugin["name"],
241 plugin["version"],
242 plugin["repository"]);
243 }
244 return;
245 }
246
247 // List available updates **not ready
248 private void HandleConsoleListUpdates(string module, string[] cmd)
249 {
250 PluginManager.ListUpdates();
251 return;
252 }
253
254 // Update plugin **not ready
255 private void HandleConsoleUpdatePlugin(string module, string[] cmd)
256 {
257 MainConsole.Instance.Output(PluginManager.Update());
258 return;
259 }
260
261 // Register repository
262 private void HandleConsoleAddRepo(string module, string[] cmd)
263 {
264 if ( cmd.Length == 3)
265 {
266 PluginManager.AddRepository(cmd[2]);
267 }
268 return;
269 }
270
271 // Get repository status **not working
272 private void HandleConsoleGetRepo(string module, string[] cmd)
273 {
274 PluginManager.GetRepository();
275 return;
276 }
277
278 // Remove registered repository
279 private void HandleConsoleRemoveRepo(string module, string[] cmd)
280 {
281 if (cmd.Length == 3)
282 PluginManager.RemoveRepository(cmd);
283 return;
284 }
285
286 // Enable repository
287 private void HandleConsoleEnableRepo(string module, string[] cmd)
288 {
289 PluginManager.EnableRepository(cmd);
290 return;
291 }
292
293 // Disable repository
294 private void HandleConsoleDisableRepo(string module, string[] cmd)
295 {
296 PluginManager.DisableRepository(cmd);
297 return;
298 }
299
300 // List repositories
301 private void HandleConsoleListRepos(string module, string[] cmd)
302 {
303 Dictionary<string, object> result = new Dictionary<string, object>();
304 PluginManager.ListRepositories(out result);
305
306 var list = result.Keys.ToList();
307 list.Sort();
308 foreach (var k in list)
309 {
310 Dictionary<string, object> repo = (Dictionary<string, object>)result[k];
311 bool enabled = (bool)repo["enabled"];
312 MainConsole.Instance.OutputFormat("{0}) {1} {2}",
313 k,
314 enabled == true ? "[ ]" : "[X]",
315 repo["name"], repo["url"]);
316 }
317
318 return;
319 }
320
321 // Show description information
322 private void HandleConsoleShowAddinInfo(string module, string[] cmd)
323 {
324 if (cmd.Length >= 3)
325 {
326
327 Dictionary<string, object> result = new Dictionary<string, object>();
328
329 int ndx = Convert.ToInt16(cmd[2]);
330 PluginManager.AddinInfo(ndx, out result);
331
332 MainConsole.Instance.OutputFormat("Name: {0}\nURL: {1}\nFile: {2}\nAuthor: {3}\nCategory: {4}\nDesc: {5}",
333 result["name"],
334 result["url"],
335 result["file_name"],
336 result["author"],
337 result["category"],
338 result["description"]);
339
340 return;
341 }
342 }
343
344 // Disable plugin
345 private void HandleConsoleDisablePlugin(string module, string[] cmd)
346 {
347 PluginManager.DisablePlugin(cmd);
348 return;
349 }
350
351 // Enable plugin
352 private void HandleConsoleEnablePlugin(string module, string[] cmd)
353 {
354 PluginManager.EnablePlugin(cmd);
355 return;
356 }
357 #endregion
358 }
359} \ No newline at end of file
diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs
index 42c82cf..3f208bf 100644
--- a/OpenSim/Server/Base/ServerUtils.cs
+++ b/OpenSim/Server/Base/ServerUtils.cs
@@ -33,11 +33,163 @@ using System.Xml.Serialization;
33using System.Text; 33using System.Text;
34using System.Collections.Generic; 34using System.Collections.Generic;
35using log4net; 35using log4net;
36using Nini.Config;
36using OpenSim.Framework; 37using OpenSim.Framework;
37using OpenMetaverse; 38using OpenMetaverse;
39using Mono.Addins;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Servers;
38 42
43
44[assembly:AddinRoot("Robust", "0.1")]
39namespace OpenSim.Server.Base 45namespace OpenSim.Server.Base
40{ 46{
47 [TypeExtensionPoint(Path="/Robust/Connector", Name="RobustConnector")]
48 public interface IRobustConnector
49 {
50 string ConfigName
51 {
52 get;
53 }
54
55 bool Enabled
56 {
57 get;
58 }
59
60 string PluginPath
61 {
62 get;
63 set;
64 }
65
66 uint Configure(IConfigSource config);
67 void Initialize(IHttpServer server);
68 void Unload();
69 }
70
71 public class PluginLoader
72 {
73 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74
75 public AddinRegistry Registry
76 {
77 get;
78 private set;
79 }
80
81 public IConfigSource Config
82 {
83 get;
84 private set;
85 }
86
87 public PluginLoader(IConfigSource config, string registryPath)
88 {
89 Config = config;
90
91 Registry = new AddinRegistry(registryPath, ".");
92 suppress_console_output_(true);
93 AddinManager.Initialize(registryPath);
94 suppress_console_output_(false);
95 AddinManager.Registry.Update();
96 CommandManager commandmanager = new CommandManager(Registry);
97 AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged);
98 }
99
100 private static TextWriter prev_console_;
101 // Temporarily masking the errors reported on start
102 // This is caused by a non-managed dll in the ./bin dir
103 // when the registry is initialized. The dll belongs to
104 // libomv, which has a hard-coded path to "." for pinvoke
105 // to load the openjpeg dll
106 //
107 // Will look for a way to fix, but for now this keeps the
108 // confusion to a minimum. this was copied from our region
109 // plugin loader, we have been doing this in there for a long time.
110 //
111 public void suppress_console_output_(bool save)
112 {
113 if (save)
114 {
115 prev_console_ = System.Console.Out;
116 System.Console.SetOut(new StreamWriter(Stream.Null));
117 }
118 else
119 {
120 if (prev_console_ != null)
121 System.Console.SetOut(prev_console_);
122 }
123 }
124
125 private void OnExtensionChanged(object s, ExtensionNodeEventArgs args)
126 {
127 IRobustConnector connector = (IRobustConnector)args.ExtensionObject;
128 Addin a = Registry.GetAddin(args.ExtensionNode.Addin.Id);
129
130 if(a == null)
131 {
132 Registry.Rebuild(null);
133 a = Registry.GetAddin(args.ExtensionNode.Addin.Id);
134 }
135
136 switch(args.Change)
137 {
138 case ExtensionChange.Add:
139 if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
140 {
141 m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name);
142 connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
143 else
144 {
145 m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name);
146 connector.PluginPath = a.AddinFile;
147 }
148 LoadPlugin(connector);
149 break;
150 case ExtensionChange.Remove:
151 m_log.InfoFormat("[SERVER]: Removing {0}", a.Name);
152 UnloadPlugin(connector);
153 break;
154 }
155 }
156
157 private void LoadPlugin(IRobustConnector connector)
158 {
159 IHttpServer server = null;
160 uint port = connector.Configure(Config);
161
162 if(connector.Enabled)
163 {
164 server = GetServer(connector, port);
165 connector.Initialize(server);
166 }
167 else
168 {
169 m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName);
170 }
171 }
172
173 private void UnloadPlugin(IRobustConnector connector)
174 {
175 m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName);
176
177 connector.Unload();
178 }
179
180 private IHttpServer GetServer(IRobustConnector connector, uint port)
181 {
182 IHttpServer server;
183
184 if(port != 0)
185 server = MainServer.GetHttpServer(port);
186 else
187 server = MainServer.Instance;
188
189 return server;
190 }
191 }
192
41 public static class ServerUtils 193 public static class ServerUtils
42 { 194 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 195 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -63,20 +215,30 @@ namespace OpenSim.Server.Base
63 /// <param name="dllName"></param> 215 /// <param name="dllName"></param>
64 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param> 216 /// <param name="args">The arguments which control which constructor is invoked on the plugin</param>
65 /// <returns></returns> 217 /// <returns></returns>
66 public static T LoadPlugin<T>(string dllName, Object[] args) where T:class 218 public static T LoadPlugin<T> (string dllName, Object[] args) where T:class
67 { 219 {
68 // This is good to debug configuration problems 220 // This is good to debug configuration problems
69 //if (dllName == string.Empty) 221 //if (dllName == string.Empty)
70 // Util.PrintCallStack(); 222 // Util.PrintCallStack();
71 223
72 string[] parts = dllName.Split(new char[] {':'});
73
74 dllName = parts[0];
75
76 string className = String.Empty; 224 string className = String.Empty;
77 225
78 if (parts.Length > 1) 226 // The path for a dynamic plugin will contain ":" on Windows
79 className = parts[1]; 227 string[] parts = dllName.Split (new char[] {':'});
228
229 if (parts [0].Length > 1)
230 {
231 dllName = parts [0];
232 if (parts.Length > 1)
233 className = parts[1];
234 }
235 else
236 {
237 // This is Windows - we must replace the ":" in the path
238 dllName = String.Format ("{0}:{1}", parts [0], parts [1]);
239 if (parts.Length > 2)
240 className = parts[2];
241 }
80 242
81 return LoadPlugin<T>(dllName, className, args); 243 return LoadPlugin<T>(dllName, className, args);
82 } 244 }
@@ -333,5 +495,42 @@ namespace OpenSim.Server.Base
333 495
334 return ret; 496 return ret;
335 } 497 }
498
499 public static IConfig GetConfig(string configFile, string configName)
500 {
501 IConfig config;
502
503 if (File.Exists(configFile))
504 {
505 IConfigSource configsource = new IniConfigSource(configFile);
506 config = configsource.Configs[configName];
507 }
508 else
509 config = null;
510
511 return config;
512 }
513
514 public static IConfigSource LoadInitialConfig(string url)
515 {
516 IConfigSource source = new XmlConfigSource();
517 m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url);
518
519 // The ini file path is a http URI
520 // Try to read it
521 try
522 {
523 XmlReader r = XmlReader.Create(url);
524 IConfigSource cs = new XmlConfigSource(r);
525 source.Merge(cs);
526 }
527 catch (Exception e)
528 {
529 m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url);
530 Environment.Exit(1);
531 }
532
533 return source;
534 }
336 } 535 }
337} 536}
diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs
index 5b23149..ecd69b0 100644
--- a/OpenSim/Server/Base/ServicesServerBase.cs
+++ b/OpenSim/Server/Base/ServicesServerBase.cs
@@ -56,6 +56,12 @@ namespace OpenSim.Server.Base
56 // 56 //
57 protected string[] m_Arguments; 57 protected string[] m_Arguments;
58 58
59 public string ConfigDirectory
60 {
61 get;
62 private set;
63 }
64
59 // Run flag 65 // Run flag
60 // 66 //
61 private bool m_Running = true; 67 private bool m_Running = true;
@@ -134,6 +140,8 @@ namespace OpenSim.Server.Base
134 startupConfig = Config.Configs["Startup"]; 140 startupConfig = Config.Configs["Startup"];
135 } 141 }
136 142
143 ConfigDirectory = startupConfig.GetString("ConfigDirectory", ".");
144
137 prompt = startupConfig.GetString("Prompt", prompt); 145 prompt = startupConfig.GetString("Prompt", prompt);
138 146
139 // Allow derived classes to load config before the console is 147 // Allow derived classes to load config before the console is
@@ -242,4 +250,4 @@ namespace OpenSim.Server.Base
242 { 250 {
243 } 251 }
244 } 252 }
245} \ No newline at end of file 253}
diff --git a/OpenSim/Server/Handlers/Base/ServerConnector.cs b/OpenSim/Server/Handlers/Base/ServerConnector.cs
index 71876da..72014db 100644
--- a/OpenSim/Server/Handlers/Base/ServerConnector.cs
+++ b/OpenSim/Server/Handlers/Base/ServerConnector.cs
@@ -39,8 +39,75 @@ namespace OpenSim.Server.Handlers.Base
39 39
40 public class ServiceConnector : IServiceConnector 40 public class ServiceConnector : IServiceConnector
41 { 41 {
42 public virtual string ConfigURL
43 {
44 get { return String.Empty; }
45 }
46
47 public virtual string ConfigName
48 {
49 get;
50 protected set;
51 }
52
53 public virtual string ConfigFile
54 {
55 get;
56 protected set;
57 }
58
59 public virtual IConfigSource Config
60 {
61 get;
62 protected set;
63 }
64
65 public ServiceConnector()
66 {
67 }
68
42 public ServiceConnector(IConfigSource config, IHttpServer server, string configName) 69 public ServiceConnector(IConfigSource config, IHttpServer server, string configName)
43 { 70 {
44 } 71 }
72
73 // We call this from our plugin module to get our configuration
74 public IConfig GetConfig()
75 {
76 IConfig config = null;
77 config = ServerUtils.GetConfig(ConfigFile, ConfigName);
78
79 // Our file is not here? We can get one to bootstrap our plugin module
80 if ( config == null )
81 {
82 IConfigSource remotesource = GetConfigSource();
83
84 if (remotesource != null)
85 {
86 IniConfigSource initialconfig = new IniConfigSource();
87 initialconfig.Merge (remotesource);
88 initialconfig.Save(ConfigFile);
89 }
90
91 config = remotesource.Configs[ConfigName];
92 }
93
94 return config;
95 }
96
97 // We get our remote initial configuration for bootstrapping in case
98 // we have no configuration in our main file or in an existing
99 // modular config file. This is the last resort to bootstrap the
100 // configuration, likely a new plugin loading for the first time.
101 private IConfigSource GetConfigSource()
102 {
103 IConfigSource source = null;
104
105 source = ServerUtils.LoadInitialConfig(ConfigURL);
106
107 if (source == null)
108 System.Console.WriteLine(String.Format ("Config Url: {0} Not found!", ConfigURL));
109
110 return source;
111 }
45 } 112 }
46} 113}
diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs
index 45c13fb..8be69a9 100644
--- a/OpenSim/Server/ServerMain.cs
+++ b/OpenSim/Server/ServerMain.cs
@@ -34,6 +34,7 @@ using OpenSim.Framework.Servers;
34using OpenSim.Framework.Servers.HttpServer; 34using OpenSim.Framework.Servers.HttpServer;
35using OpenSim.Server.Base; 35using OpenSim.Server.Base;
36using OpenSim.Server.Handlers.Base; 36using OpenSim.Server.Handlers.Base;
37using Mono.Addins;
37 38
38namespace OpenSim.Server 39namespace OpenSim.Server
39{ 40{
@@ -48,9 +49,13 @@ namespace OpenSim.Server
48 protected static List<IServiceConnector> m_ServiceConnectors = 49 protected static List<IServiceConnector> m_ServiceConnectors =
49 new List<IServiceConnector>(); 50 new List<IServiceConnector>();
50 51
52 protected static PluginLoader loader;
53
51 public static int Main(string[] args) 54 public static int Main(string[] args)
52 { 55 {
53 m_Server = new HttpServerBase("R.O.B.U.S.T.", args); 56 m_Server = new HttpServerBase("R.O.B.U.S.T.", args);
57
58 string registryLocation;
54 59
55 IConfig serverConfig = m_Server.Config.Configs["Startup"]; 60 IConfig serverConfig = m_Server.Config.Configs["Startup"];
56 if (serverConfig == null) 61 if (serverConfig == null)
@@ -60,6 +65,8 @@ namespace OpenSim.Server
60 } 65 }
61 66
62 string connList = serverConfig.GetString("ServiceConnectors", String.Empty); 67 string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
68
69 registryLocation = serverConfig.GetString("RegistryLocation",".");
63 70
64 IConfig servicesConfig = m_Server.Config.Configs["ServiceList"]; 71 IConfig servicesConfig = m_Server.Config.Configs["ServiceList"];
65 if (servicesConfig != null) 72 if (servicesConfig != null)
@@ -141,6 +148,9 @@ namespace OpenSim.Server
141 m_log.InfoFormat("[SERVER]: Failed to load {0}", conn); 148 m_log.InfoFormat("[SERVER]: Failed to load {0}", conn);
142 } 149 }
143 } 150 }
151
152 loader = new PluginLoader(m_Server.Config, registryLocation);
153
144 int res = m_Server.Run(); 154 int res = m_Server.Run();
145 155
146 Environment.Exit(res); 156 Environment.Exit(res);
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
index 508baf7..ef2494a 100644
--- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
@@ -315,7 +315,7 @@ namespace OpenSim.Services.Connectors.Simulation
315 315
316 try 316 try
317 { 317 {
318 OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 10000, false); 318 OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false);
319 bool success = result["success"].AsBoolean(); 319 bool success = result["success"].AsBoolean();
320 if (result.ContainsKey("_Result")) 320 if (result.ContainsKey("_Result"))
321 { 321 {
diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
index 0c9cfd3..e8d7cca 100644
--- a/OpenSim/Services/HypergridService/HGInstantMessageService.cs
+++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
@@ -61,13 +61,13 @@ namespace OpenSim.Services.HypergridService
61 protected static IGridService m_GridService; 61 protected static IGridService m_GridService;
62 protected static IPresenceService m_PresenceService; 62 protected static IPresenceService m_PresenceService;
63 protected static IUserAgentService m_UserAgentService; 63 protected static IUserAgentService m_UserAgentService;
64 protected static IOfflineIMService m_OfflineIMService;
64 65
65 protected static IInstantMessageSimConnector m_IMSimConnector; 66 protected static IInstantMessageSimConnector m_IMSimConnector;
66 67
67 protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>(); 68 protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
68 private static ExpiringCache<UUID, GridRegion> m_RegionCache; 69 private static ExpiringCache<UUID, GridRegion> m_RegionCache;
69 70
70 private static string m_RestURL;
71 private static bool m_ForwardOfflineGroupMessages; 71 private static bool m_ForwardOfflineGroupMessages;
72 private static bool m_InGatekeeper; 72 private static bool m_InGatekeeper;
73 73
@@ -111,9 +111,14 @@ namespace OpenSim.Services.HypergridService
111 return; 111 return;
112 } 112 }
113 113
114 m_RestURL = cnf.GetString("OfflineMessageURL", string.Empty);
115 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false); 114 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false);
116 115
116 if (m_InGatekeeper)
117 {
118 string offlineIMService = cnf.GetString("OfflineIMService", string.Empty);
119 if (offlineIMService != string.Empty)
120 m_OfflineIMService = ServerUtils.LoadPlugin<IOfflineIMService>(offlineIMService, args);
121 }
117 } 122 }
118 } 123 }
119 124
@@ -329,18 +334,28 @@ namespace OpenSim.Services.HypergridService
329 334
330 private bool UndeliveredMessage(GridInstantMessage im) 335 private bool UndeliveredMessage(GridInstantMessage im)
331 { 336 {
332 if (m_RestURL != string.Empty && (im.offline != 0) 337 if (m_OfflineIMService == null)
333 && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) 338 return false;
334 {
335// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
336 339
337 return SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( 340 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
338 "POST", m_RestURL + "/SaveMessage/", im); 341 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
339 } 342 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
340 else 343 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
344 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
341 { 345 {
342 return false; 346 return false;
343 } 347 }
348
349 if (!m_ForwardOfflineGroupMessages)
350 {
351 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
352 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
353 return false;
354 }
355
356// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
357 string reason = string.Empty;
358 return m_OfflineIMService.StoreMessage(im, out reason);
344 } 359 }
345 } 360 }
346} \ No newline at end of file 361} \ No newline at end of file
diff --git a/OpenSim/Services/Interfaces/IOfflineIMService.cs b/OpenSim/Services/Interfaces/IOfflineIMService.cs
new file mode 100644
index 0000000..2848967
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IOfflineIMService.cs
@@ -0,0 +1,115 @@
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 */
27using System;
28using System.Collections.Generic;
29
30using OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Services.Interfaces
34{
35 public interface IOfflineIMService
36 {
37 List<GridInstantMessage> GetMessages(UUID principalID);
38 bool StoreMessage(GridInstantMessage im, out string reason);
39 }
40
41 public class OfflineIMDataUtils
42 {
43 public static GridInstantMessage GridInstantMessage(Dictionary<string, object> dict)
44 {
45 GridInstantMessage im = new GridInstantMessage();
46
47 if (dict.ContainsKey("BinaryBucket") && dict["BinaryBucket"] != null)
48 im.binaryBucket = OpenMetaverse.Utils.HexStringToBytes(dict["BinaryBucket"].ToString(), true);
49
50 if (dict.ContainsKey("Dialog") && dict["Dialog"] != null)
51 im.dialog = byte.Parse(dict["Dialog"].ToString());
52
53 if (dict.ContainsKey("FromAgentID") && dict["FromAgentID"] != null)
54 im.fromAgentID = new Guid(dict["FromAgentID"].ToString());
55
56 if (dict.ContainsKey("FromAgentName") && dict["FromAgentName"] != null)
57 im.fromAgentName = dict["FromAgentName"].ToString();
58 else
59 im.fromAgentName = string.Empty;
60
61 if (dict.ContainsKey("FromGroup") && dict["FromGroup"] != null)
62 im.fromGroup = bool.Parse(dict["FromGroup"].ToString());
63
64 if (dict.ContainsKey("SessionID") && dict["SessionID"] != null)
65 im.imSessionID = new Guid(dict["SessionID"].ToString());
66
67 if (dict.ContainsKey("Message") && dict["Message"] != null)
68 im.message = dict["Message"].ToString();
69 else
70 im.message = string.Empty;
71
72 if (dict.ContainsKey("Offline") && dict["Offline"] != null)
73 im.offline = byte.Parse(dict["Offline"].ToString());
74
75 if (dict.ContainsKey("EstateID") && dict["EstateID"] != null)
76 im.ParentEstateID = UInt32.Parse(dict["EstateID"].ToString());
77
78 if (dict.ContainsKey("Position") && dict["Position"] != null)
79 im.Position = Vector3.Parse(dict["Position"].ToString());
80
81 if (dict.ContainsKey("RegionID") && dict["RegionID"] != null)
82 im.RegionID = new Guid(dict["RegionID"].ToString());
83
84 if (dict.ContainsKey("Timestamp") && dict["Timestamp"] != null)
85 im.timestamp = UInt32.Parse(dict["Timestamp"].ToString());
86
87 if (dict.ContainsKey("ToAgentID") && dict["ToAgentID"] != null)
88 im.toAgentID = new Guid(dict["ToAgentID"].ToString());
89
90 return im;
91 }
92
93 public static Dictionary<string, object> GridInstantMessage(GridInstantMessage im)
94 {
95 Dictionary<string, object> dict = new Dictionary<string, object>();
96
97 dict["BinaryBucket"] = OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, im.binaryBucket.Length, null);
98 dict["Dialog"] = im.dialog.ToString();
99 dict["FromAgentID"] = im.fromAgentID.ToString();
100 dict["FromAgentName"] = im.fromAgentName == null ? string.Empty : im.fromAgentName;
101 dict["FromGroup"] = im.fromGroup.ToString();
102 dict["SessionID"] = im.imSessionID.ToString();
103 dict["Message"] = im.message == null ? string.Empty : im.message;
104 dict["Offline"] = im.offline.ToString();
105 dict["EstateID"] = im.ParentEstateID.ToString();
106 dict["Position"] = im.Position.ToString();
107 dict["RegionID"] = im.RegionID.ToString();
108 dict["Timestamp"] = im.timestamp.ToString();
109 dict["ToAgentID"] = im.toAgentID.ToString();
110
111 return dict;
112 }
113
114 }
115}
diff --git a/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs b/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs
index 6fb9df1..3035cea 100644
--- a/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs
+++ b/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs
@@ -26,12 +26,15 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
31using log4net; 32using log4net;
32using Mono.Addins; 33using Mono.Addins;
33using Nini.Config; 34using Nini.Config;
34using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Data;
37using OpenSim.Data.Null;
35using OpenSim.Framework; 38using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
@@ -44,6 +47,8 @@ namespace OpenSim.Tests.Common.Mock
44 { 47 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 49
50 IXGroupData m_data = new NullXGroupData(null, null);
51
47 public string Name 52 public string Name
48 { 53 {
49 get { return "MockGroupsServicesConnector"; } 54 get { return "MockGroupsServicesConnector"; }
@@ -84,7 +89,33 @@ namespace OpenSim.Tests.Common.Mock
84 int membershipFee, bool openEnrollment, bool allowPublish, 89 int membershipFee, bool openEnrollment, bool allowPublish,
85 bool maturePublish, UUID founderID) 90 bool maturePublish, UUID founderID)
86 { 91 {
87 return UUID.Zero; 92 XGroup group = new XGroup()
93 {
94 groupID = UUID.Random(),
95 ownerRoleID = UUID.Random(),
96 name = name,
97 charter = charter,
98 showInList = showInList,
99 insigniaID = insigniaID,
100 membershipFee = membershipFee,
101 openEnrollment = openEnrollment,
102 allowPublish = allowPublish,
103 maturePublish = maturePublish,
104 founderID = founderID,
105 everyonePowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultEveryonePowers,
106 ownersPowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultOwnerPowers
107 };
108
109 if (m_data.StoreGroup(group))
110 {
111 m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: Created group {0} {1}", group.name, group.groupID);
112 return group.groupID;
113 }
114 else
115 {
116 m_log.ErrorFormat("[MOCK GROUPS SERVICES CONNECTOR]: Failed to create group {0}", name);
117 return UUID.Zero;
118 }
88 } 119 }
89 120
90 public void UpdateGroup(UUID requestingAgentID, UUID groupID, string charter, bool showInList, 121 public void UpdateGroup(UUID requestingAgentID, UUID groupID, string charter, bool showInList,
@@ -107,9 +138,49 @@ namespace OpenSim.Tests.Common.Mock
107 { 138 {
108 } 139 }
109 140
110 public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID GroupID, string GroupName) 141 public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID groupID, string groupName)
111 { 142 {
112 return null; 143 m_log.DebugFormat(
144 "[MOCK GROUPS SERVICES CONNECTOR]: Processing GetGroupRecord() for groupID {0}, name {1}",
145 groupID, groupName);
146
147 XGroup[] groups;
148 string field, val;
149
150 if (groupID != UUID.Zero)
151 {
152 field = "groupID";
153 val = groupID.ToString();
154 }
155 else
156 {
157 field = "name";
158 val = groupName;
159 }
160
161 groups = m_data.GetGroups(field, val);
162
163 if (groups.Length == 0)
164 return null;
165
166 XGroup xg = groups[0];
167
168 GroupRecord gr = new GroupRecord()
169 {
170 GroupID = xg.groupID,
171 GroupName = xg.name,
172 AllowPublish = xg.allowPublish,
173 MaturePublish = xg.maturePublish,
174 Charter = xg.charter,
175 FounderID = xg.founderID,
176 // FIXME: group picture storage location unknown
177 MembershipFee = xg.membershipFee,
178 OpenEnrollment = xg.openEnrollment,
179 OwnerRoleID = xg.ownerRoleID,
180 ShowInList = xg.showInList
181 };
182
183 return gr;
113 } 184 }
114 185
115 public GroupProfileData GetMemberGroupProfile(UUID requestingAgentID, UUID GroupID, UUID AgentID) 186 public GroupProfileData GetMemberGroupProfile(UUID requestingAgentID, UUID GroupID, UUID AgentID)
diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
index f9bf768..ccbdf81 100644
--- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
+++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs
@@ -33,10 +33,11 @@ using log4net;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Data; 35using OpenSim.Data;
36using OpenSim.Data.Null;
36 37
37namespace OpenSim.Tests.Common.Mock 38namespace OpenSim.Tests.Common.Mock
38{ 39{
39 public class TestXInventoryDataPlugin : IXInventoryData 40 public class TestXInventoryDataPlugin : NullGenericDataHandler, IXInventoryData
40 { 41 {
41 private Dictionary<UUID, XInventoryFolder> m_allFolders = new Dictionary<UUID, XInventoryFolder>(); 42 private Dictionary<UUID, XInventoryFolder> m_allFolders = new Dictionary<UUID, XInventoryFolder>();
42 private Dictionary<UUID, XInventoryItem> m_allItems = new Dictionary<UUID, XInventoryItem>(); 43 private Dictionary<UUID, XInventoryItem> m_allItems = new Dictionary<UUID, XInventoryItem>();
@@ -58,28 +59,6 @@ namespace OpenSim.Tests.Common.Mock
58 return origFolders.Select(f => f.Clone()).ToArray(); 59 return origFolders.Select(f => f.Clone()).ToArray();
59 } 60 }
60 61
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) 62 public bool StoreFolder(XInventoryFolder folder)
84 { 63 {
85 m_allFolders[folder.folderID] = folder.Clone(); 64 m_allFolders[folder.folderID] = folder.Clone();
diff --git a/OpenSim/Tests/ConfigurationLoaderTest.cs b/OpenSim/Tests/ConfigurationLoaderTest.cs
index 067264d..e5186ae 100644
--- a/OpenSim/Tests/ConfigurationLoaderTest.cs
+++ b/OpenSim/Tests/ConfigurationLoaderTest.cs
@@ -29,11 +29,12 @@ using System.IO;
29using Nini.Config; 29using Nini.Config;
30using NUnit.Framework; 30using NUnit.Framework;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Tests.Common;
32 33
33namespace OpenSim.Tests 34namespace OpenSim.Tests
34{ 35{
35 [TestFixture] 36 [TestFixture]
36 public class ConfigurationLoaderTests 37 public class ConfigurationLoaderTests : OpenSimTestCase
37 { 38 {
38 private const string m_testSubdirectory = "test"; 39 private const string m_testSubdirectory = "test";
39 private string m_basePath; 40 private string m_basePath;
diff --git a/OpenSim/Tests/Performance/NPCPerformanceTests.cs b/OpenSim/Tests/Performance/NPCPerformanceTests.cs
index 627765b..2026a88 100644
--- a/OpenSim/Tests/Performance/NPCPerformanceTests.cs
+++ b/OpenSim/Tests/Performance/NPCPerformanceTests.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Tests.Performance
58 /// earlier tests. 58 /// earlier tests.
59 /// </remarks> 59 /// </remarks>
60 [TestFixture] 60 [TestFixture]
61 public class NPCPerformanceTests 61 public class NPCPerformanceTests : OpenSimTestCase
62 { 62 {
63 private TestScene scene; 63 private TestScene scene;
64 private AvatarFactoryModule afm; 64 private AvatarFactoryModule afm;
diff --git a/OpenSim/Tests/Performance/ObjectPerformanceTests.cs b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs
index 2264d86..656a971 100644
--- a/OpenSim/Tests/Performance/ObjectPerformanceTests.cs
+++ b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Tests.Performance
47 /// earlier tests. 47 /// earlier tests.
48 /// </remarks> 48 /// </remarks>
49 [TestFixture] 49 [TestFixture]
50 public class ObjectPerformanceTests 50 public class ObjectPerformanceTests : OpenSimTestCase
51 { 51 {
52 [TearDown] 52 [TearDown]
53 public void TearDown() 53 public void TearDown()
diff --git a/OpenSim/Tests/Performance/ScriptPerformanceTests.cs b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs
index d708abd..4064edc 100644
--- a/OpenSim/Tests/Performance/ScriptPerformanceTests.cs
+++ b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs
@@ -53,7 +53,7 @@ namespace OpenSim.Tests.Performance
53 /// earlier tests. 53 /// earlier tests.
54 /// </remarks> 54 /// </remarks>
55 [TestFixture] 55 [TestFixture]
56 public class ScriptPerformanceTests 56 public class ScriptPerformanceTests : OpenSimTestCase
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/bin/Mono.Addins.CecilReflector.dll b/bin/Mono.Addins.CecilReflector.dll
index a1a6382..9ca4631 100755
--- a/bin/Mono.Addins.CecilReflector.dll
+++ b/bin/Mono.Addins.CecilReflector.dll
Binary files differ
diff --git a/bin/Mono.Addins.Setup.dll b/bin/Mono.Addins.Setup.dll
index 8aa6d5f..75773aa 100755
--- a/bin/Mono.Addins.Setup.dll
+++ b/bin/Mono.Addins.Setup.dll
Binary files differ
diff --git a/bin/Mono.Addins.dll b/bin/Mono.Addins.dll
index ea330fd..326ed1d 100755
--- a/bin/Mono.Addins.dll
+++ b/bin/Mono.Addins.dll
Binary files differ
diff --git a/bin/OpenMetaverse.dll.config b/bin/OpenMetaverse.dll.config
index b67da5f..f5423b2 100644
--- a/bin/OpenMetaverse.dll.config
+++ b/bin/OpenMetaverse.dll.config
@@ -1,5 +1,5 @@
1<configuration> 1<configuration>
2 <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.5.0-dotnet-1.dylib" /> 2 <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet.dylib" />
3 <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" /> 3 <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
4 <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" /> 4 <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
5</configuration> 5</configuration>
diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config
index e3107ab..8a891f4 100755
--- a/bin/OpenSim.exe.config
+++ b/bin/OpenSim.exe.config
@@ -32,9 +32,15 @@
32 <appender-ref ref="LogFileAppender" /> 32 <appender-ref ref="LogFileAppender" />
33 </root> 33 </root>
34 34
35 <!-- Independently control logging level for XEngine -->
35 <logger name="OpenSim.Region.ScriptEngine.XEngine"> 36 <logger name="OpenSim.Region.ScriptEngine.XEngine">
36 <level value="INFO"/> 37 <level value="INFO"/>
37 </logger> 38 </logger>
38 39
40 <!-- Independently control logging level for per region module loading -->
41 <logger name="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin">
42 <level value="INFO"/>
43 </logger>
44
39 </log4net> 45 </log4net>
40</configuration> 46</configuration>
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 54f252e..9bfab4a 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -217,10 +217,10 @@
217 ; to false if you have compatibility problems. 217 ; to false if you have compatibility problems.
218 ;CacheSculptMaps = true 218 ;CacheSculptMaps = true
219 219
220 ; Choose one of the physics engines below 220 ; Choose one of the physics engines below.
221 ; OpenDynamicsEngine is by some distance the most developed physics engine 221 ; OpenDynamicsEngine is by some distance the most developed physics engine.
222 ; basicphysics effectively does not model physics at all, making all objects phantom 222 ; BulletSim is a high performance, up-and-coming physics engine.
223 223 ; basicphysics effectively does not model physics at all, making all objects phantom.
224 physics = OpenDynamicsEngine 224 physics = OpenDynamicsEngine
225 ;physics = basicphysics 225 ;physics = basicphysics
226 ;physics = POS 226 ;physics = POS
@@ -364,6 +364,12 @@
364 ; alert_uri = "http://myappserver.net/my_handler/" 364 ; alert_uri = "http://myappserver.net/my_handler/"
365 365
366 366
367[EstateManagement]
368 ; If false, then block any region restart requests from the client even if they are otherwise valid.
369 ; Default is true
370 AllowRegionRestartFromClient = true
371
372
367[SMTP] 373[SMTP]
368 enabled = false 374 enabled = false
369 375
@@ -898,15 +904,18 @@
898 904
899[BulletSim] 905[BulletSim]
900 ; World parameters 906 ; World parameters
901 DefaultFriction = 0.50 907 DefaultFriction = 0.20
902 DefaultDensity = 10.000006836 908 DefaultDensity = 10.000006836
903 DefaultRestitution = 0.0 909 DefaultRestitution = 0.0
904 Gravity = -9.80665 910 Gravity = -9.80665
905 911
906 TerrainFriction = 0.50 912 TerrainFriction = 0.30
907 TerrainHitFriction = 0.8 913 TerrainHitFraction = 0.8
908 TerrainRestitution = 0 914 TerrainRestitution = 0
915 TerrainCollisionMargin = 0.04
916
909 AvatarFriction = 0.2 917 AvatarFriction = 0.2
918 AvatarStandingFriction = 0.99
910 AvatarRestitution = 0.0 919 AvatarRestitution = 0.0
911 AvatarDensity = 60.0 920 AvatarDensity = 60.0
912 AvatarCapsuleWidth = 0.6 921 AvatarCapsuleWidth = 0.6
@@ -920,27 +929,15 @@
920 LinearDamping = 0.0 929 LinearDamping = 0.0
921 AngularDamping = 0.0 930 AngularDamping = 0.0
922 DeactivationTime = 0.2 931 DeactivationTime = 0.2
923 LinearSleepingThreshold = 0.8 932 CollisionMargin = 0.04
924 AngularSleepingThreshold = 1.0
925 CcdMotionThreshold = 0.0
926 CcdSweptSphereRadius = 0.0
927 ContactProcessingThreshold = 0.1
928 ; If setting a pool size, also disable dynamic allocation (default pool size is 4096 with dynamic alloc)
929 MaxPersistantManifoldPoolSize = 0
930 ShouldDisableContactPoolDynamicAllocation = False
931 ShouldForceUpdateAllAabbs = False
932 ShouldRandomizeSolverOrder = True
933 ShouldSplitSimulationIslands = True
934 ShouldEnableFrictionCaching = False
935 NumberOfSolverIterations = 0
936 933
937 ; Linkset constraint parameters 934 ; Linkset constraint parameters
935 LinkImplementation = 1 ; 0=constraint, 1=compound
938 LinkConstraintUseFrameOffset = False 936 LinkConstraintUseFrameOffset = False
939 LinkConstraintEnableTransMotor = True 937 LinkConstraintEnableTransMotor = True
940 LinkConstraintTransMotorMaxVel = 5.0 938 LinkConstraintTransMotorMaxVel = 5.0
941 LinkConstraintTransMotorMaxForce = 0.1 939 LinkConstraintTransMotorMaxForce = 0.1
942 940
943
944 ; Whether to mesh sculpties 941 ; Whether to mesh sculpties
945 MeshSculptedPrim = true 942 MeshSculptedPrim = true
946 943
@@ -1367,6 +1364,10 @@
1367 ; If a script overruns it's event limit, kill the script? 1364 ; If a script overruns it's event limit, kill the script?
1368 KillTimedOutScripts = false 1365 KillTimedOutScripts = false
1369 1366
1367 ; Amount of time in milliseconds we will wait for an event to completely normally when a script stop is requested
1368 ; before aborting the thread (such as when an object containing scripts is taken into inventory).
1369 WaitForEventCompletionOnScriptStop = 1000;
1370
1370 ; Sets the multiplier for the scripting delays 1371 ; Sets the multiplier for the scripting delays
1371 ScriptDelayFactor = 1.0 1372 ScriptDelayFactor = 1.0
1372 1373
@@ -1582,8 +1583,7 @@
1582 1583
1583 ; If true, then the basic packet objects used to receive data are also recycled, not just the LLUDP packets. 1584 ; If true, then the basic packet objects used to receive data are also recycled, not just the LLUDP packets.
1584 ; This reduces data churn 1585 ; This reduces data churn
1585 ; This setting is currently experimental and defaults to false. 1586 RecycleBaseUDPPackets = true
1586 RecycleBaseUDPPackets = false;
1587 1587
1588 1588
1589[InterestManagement] 1589[InterestManagement]
diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example
index 4ecc6b0..c7d4b7f 100644
--- a/bin/Robust.HG.ini.example
+++ b/bin/Robust.HG.ini.example
@@ -22,6 +22,18 @@
22; * 22; *
23[Startup] 23[Startup]
24 24
25; Plugin Registry Location
26; Set path to directory for plugin registry. Information
27; about the registered repositories and installed plugins
28; will be stored here
29; The Robust.exe process must hvae R/W access to the location
30RegistryLocation = "."
31
32; Modular configurations
33; Set path to directory for modular ini files...
34; The Robust.exe process must hvae R/W access to the location
35ConfigDirectory = "/home/opensim/etc/Configs"
36
25[ServiceList] 37[ServiceList]
26 38
27AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector" 39AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
@@ -53,7 +65,6 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
53;; Additions for other add-on modules. For example: 65;; Additions for other add-on modules. For example:
54;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector" 66;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector"
55 67
56
57; * This is common for all services, it's the network setup for the entire 68; * This is common for all services, it's the network setup for the entire
58; * server instance, if none is specified above 69; * server instance, if none is specified above
59; * 70; *
diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example
index 7503c5e..bc5cbcc 100644
--- a/bin/Robust.ini.example
+++ b/bin/Robust.ini.example
@@ -14,6 +14,19 @@
14; * 14; *
15[Startup] 15[Startup]
16 16
17; Plugin Registry Location
18; Set path to directory for plugin registry. Information
19; about the registered repositories and installed plugins
20; will be stored here
21; The Robust.exe process must hvae R/W access to the location
22RegistryLocation = "."
23
24
25; Modular configurations
26; Set path to directory for modular ini files...
27; The Robust.exe process must hvae R/W access to the location
28ConfigDirectory = "/home/opensim/etc/Configs"
29
17[ServiceList] 30[ServiceList]
18AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector" 31AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
19InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector" 32InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example
index 79f7ed6..e53fcca 100644
--- a/bin/config-include/GridCommon.ini.example
+++ b/bin/config-include/GridCommon.ini.example
@@ -137,6 +137,11 @@
137 ;; uncomment the next line. You may want to do this on sims that have licensed content. 137 ;; uncomment the next line. You may want to do this on sims that have licensed content.
138 ; OutboundPermission = False 138 ; OutboundPermission = False
139 139
140 ;; Send visual reminder to local users that their inventories are unavailable while they are traveling
141 ;; and available when they return. True by default.
142 ;RestrictInventoryAccessAbroad = True
143
144
140[HGAssetService] 145[HGAssetService]
141 ; 146 ;
142 ; === HG ONLY === 147 ; === HG ONLY ===
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll
index 2ae1c75..9834faa 100755
--- a/bin/lib32/BulletSim.dll
+++ b/bin/lib32/BulletSim.dll
Binary files differ
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so
index d4852a5..3c8e034 100755
--- a/bin/lib32/libBulletSim.so
+++ b/bin/lib32/libBulletSim.so
Binary files differ
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll
index 77cf7e3..75999f0 100755
--- a/bin/lib64/BulletSim.dll
+++ b/bin/lib64/BulletSim.dll
Binary files differ
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so
index 4ec62b2..a8a4720 100755
--- a/bin/lib64/libBulletSim.so
+++ b/bin/lib64/libBulletSim.so
Binary files differ
diff --git a/prebuild.xml b/prebuild.xml
index 7fff2e0..ebf0f1f 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -105,6 +105,7 @@
105 <Reference name="Nini" path="../../bin/"/> 105 <Reference name="Nini" path="../../bin/"/>
106 <Reference name="log4net" path="../../bin/"/> 106 <Reference name="log4net" path="../../bin/"/>
107 <Reference name="Mono.Addins" path="../../bin/"/> 107 <Reference name="Mono.Addins" path="../../bin/"/>
108 <Reference name="Mono.Addins.Setup" path="../../bin/"/>
108 <Reference name="SmartThreadPool"/> 109 <Reference name="SmartThreadPool"/>
109 <Files> 110 <Files>
110 <Match pattern="*.cs" recurse="false"/> 111 <Match pattern="*.cs" recurse="false"/>
@@ -851,10 +852,14 @@
851 852
852 <ReferencePath>../../../bin/</ReferencePath> 853 <ReferencePath>../../../bin/</ReferencePath>
853 <Reference name="System"/> 854 <Reference name="System"/>
855 <Reference name="System.Core"/>
854 <Reference name="System.Xml"/> 856 <Reference name="System.Xml"/>
855 <Reference name="System.Web"/> 857 <Reference name="System.Web"/>
856 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 858 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
859 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
857 <Reference name="OpenMetaverse" path="../../../bin/"/> 860 <Reference name="OpenMetaverse" path="../../../bin/"/>
861 <Reference name="Mono.Addins" path="../../../bin/"/>
862 <Reference name="Mono.Addins.Setup" path="../../../bin/"/>
858 <Reference name="OpenSim.Framework"/> 863 <Reference name="OpenSim.Framework"/>
859 <Reference name="OpenSim.Framework.Console"/> 864 <Reference name="OpenSim.Framework.Console"/>
860 <Reference name="OpenSim.Framework.Servers"/> 865 <Reference name="OpenSim.Framework.Servers"/>
@@ -977,6 +982,7 @@
977 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 982 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
978 <Reference name="OpenMetaverse" path="../../../bin/"/> 983 <Reference name="OpenMetaverse" path="../../../bin/"/>
979 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/> 984 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
985 <Reference name="Mono.Addins" path="../../../bin/"/>
980 <Reference name="OpenSim.Data"/> 986 <Reference name="OpenSim.Data"/>
981 <Reference name="OpenSim.Framework"/> 987 <Reference name="OpenSim.Framework"/>
982 <Reference name="OpenSim.Framework.Communications"/> 988 <Reference name="OpenSim.Framework.Communications"/>
@@ -985,7 +991,6 @@
985 <Reference name="OpenSim.Server.Base"/> 991 <Reference name="OpenSim.Server.Base"/>
986 <Reference name="OpenSim.Services.Base"/> 992 <Reference name="OpenSim.Services.Base"/>
987 <Reference name="OpenSim.Services.Interfaces"/> 993 <Reference name="OpenSim.Services.Interfaces"/>
988 <Reference name="Mono.Addins" path="../../../bin/"/>
989 <Reference name="Nini" path="../../../bin/"/> 994 <Reference name="Nini" path="../../../bin/"/>
990 <Reference name="log4net" path="../../../bin/"/> 995 <Reference name="log4net" path="../../../bin/"/>
991 <Reference name="XMLRPC" path="../../../bin/"/> 996 <Reference name="XMLRPC" path="../../../bin/"/>
@@ -1384,6 +1389,7 @@
1384 <Reference name="Nini" path="../../../bin/"/> 1389 <Reference name="Nini" path="../../../bin/"/>
1385 <Reference name="log4net" path="../../../bin/"/> 1390 <Reference name="log4net" path="../../../bin/"/>
1386 <Reference name="DotNetOpenId" path="../../../bin/"/> 1391 <Reference name="DotNetOpenId" path="../../../bin/"/>
1392 <Reference name="Mono.Addins" path="../../../bin/"/>
1387 1393
1388 <Files> 1394 <Files>
1389 <Match pattern="*.cs" recurse="true"> 1395 <Match pattern="*.cs" recurse="true">
@@ -1460,6 +1466,8 @@
1460 <Reference name="OpenSim.Server.Handlers"/> 1466 <Reference name="OpenSim.Server.Handlers"/>
1461 <Reference name="Nini" path="../../bin/"/> 1467 <Reference name="Nini" path="../../bin/"/>
1462 <Reference name="log4net" path="../../bin/"/> 1468 <Reference name="log4net" path="../../bin/"/>
1469 <Reference name="Mono.Addins" path="../../bin/"/>
1470 <Reference name="Mono.Addins.Setup" path="../../bin/"/>
1463 1471
1464 <Files> 1472 <Files>
1465 <Match pattern="*.cs" recurse="false"> 1473 <Match pattern="*.cs" recurse="false">
@@ -1799,6 +1807,7 @@
1799 1807
1800 <ReferencePath>../../../bin/</ReferencePath> 1808 <ReferencePath>../../../bin/</ReferencePath>
1801 <Reference name="System"/> 1809 <Reference name="System"/>
1810 <Reference name="System.Core"/>
1802 <Reference name="System.Xml"/> 1811 <Reference name="System.Xml"/>
1803 <Reference name="OpenSim.Data"/> 1812 <Reference name="OpenSim.Data"/>
1804 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 1813 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
@@ -2167,7 +2176,7 @@
2167 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 2176 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
2168 <Reference name="OpenMetaverse" path="../../../bin/"/> 2177 <Reference name="OpenMetaverse" path="../../../bin/"/>
2169 <Reference name="Nini" path="../../../bin/"/> 2178 <Reference name="Nini" path="../../../bin/"/>
2170 <Reference name="Mono.Addins"/> 2179 <Reference name="Mono.Addins" path="../../../bin/"/>
2171 <Reference name="log4net" path="../../../bin/"/> 2180 <Reference name="log4net" path="../../../bin/"/>
2172 <Files> 2181 <Files>
2173 <Match pattern="*.cs" recurse="true"/> 2182 <Match pattern="*.cs" recurse="true"/>
@@ -2576,7 +2585,7 @@
2576 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 2585 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
2577 <Reference name="OpenSim.Region.Physics.Manager"/> 2586 <Reference name="OpenSim.Region.Physics.Manager"/>
2578 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/> 2587 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
2579 <Reference name="Mono.Addins"/> 2588 <Reference name="Mono.Addins" path="../../../bin/"/>
2580 2589
2581 <!-- For scripting in funny languages by default --> 2590 <!-- For scripting in funny languages by default -->
2582 <Reference name="XMLRPC" path="../../../bin/"/> 2591 <Reference name="XMLRPC" path="../../../bin/"/>
@@ -2807,12 +2816,13 @@
2807 <Reference name="nunit.framework" path="../../../bin/"/> 2816 <Reference name="nunit.framework" path="../../../bin/"/>
2808 <Reference name="OpenMetaverse" path="../../../bin/"/> 2817 <Reference name="OpenMetaverse" path="../../../bin/"/>
2809 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 2818 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
2819 <Reference name="OpenSim.Data"/>
2820 <Reference name="OpenSim.Data.Null"/>
2810 <Reference name="OpenSim.Framework"/> 2821 <Reference name="OpenSim.Framework"/>
2811 <Reference name="OpenSim.Framework.Communications"/> 2822 <Reference name="OpenSim.Framework.Communications"/>
2812 <Reference name="OpenSim.Framework.Console"/> 2823 <Reference name="OpenSim.Framework.Console"/>
2813 <Reference name="OpenSim.Framework.Servers"/> 2824 <Reference name="OpenSim.Framework.Servers"/>
2814 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 2825 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
2815 <Reference name="OpenSim.Data"/>
2816 <Reference name="OpenSim.Services.Interfaces"/> 2826 <Reference name="OpenSim.Services.Interfaces"/>
2817 <Reference name="OpenSim.Server.Base"/> 2827 <Reference name="OpenSim.Server.Base"/>
2818 <Reference name="OpenSim.Region.Framework"/> 2828 <Reference name="OpenSim.Region.Framework"/>
@@ -2838,10 +2848,11 @@
2838 </Configuration> 2848 </Configuration>
2839 2849
2840 <ReferencePath>../../bin/</ReferencePath> 2850 <ReferencePath>../../bin/</ReferencePath>
2841 <Reference name="OpenSim.Framework"/>
2842 <Reference name="Nini" path="../../bin/"/> 2851 <Reference name="Nini" path="../../bin/"/>
2843 <Reference name="nunit.framework" path="../../bin/"/> 2852 <Reference name="nunit.framework" path="../../bin/"/>
2844 <Reference name="OpenSim"/> 2853 <Reference name="OpenSim"/>
2854 <Reference name="OpenSim.Framework"/>
2855 <Reference name="OpenSim.Tests.Common"/>
2845 <Files> 2856 <Files>
2846 <Match pattern="*.cs" recurse="false"/> 2857 <Match pattern="*.cs" recurse="false"/>
2847 </Files> 2858 </Files>
@@ -3104,6 +3115,7 @@
3104 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 3115 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
3105 <Reference name="OpenSim.Region.Framework"/> 3116 <Reference name="OpenSim.Region.Framework"/>
3106 <Reference name="OpenSim.Region.CoreModules"/> 3117 <Reference name="OpenSim.Region.CoreModules"/>
3118 <Reference name="OpenSim.Region.OptionalModules"/>
3107 <Reference name="OpenSim.Region.Physics.Manager"/> 3119 <Reference name="OpenSim.Region.Physics.Manager"/>
3108 <Reference name="OpenSim.Region.ScriptEngine.Shared"/> 3120 <Reference name="OpenSim.Region.ScriptEngine.Shared"/>
3109 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/> 3121 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/>
@@ -3414,6 +3426,7 @@
3414 <Reference name="OpenSim.Framework.Console"/> 3426 <Reference name="OpenSim.Framework.Console"/>
3415 <Reference name="OpenSim.Region.Physics.Manager"/> 3427 <Reference name="OpenSim.Region.Physics.Manager"/>
3416 <Reference name="OpenSim.Region.Physics.OdePlugin" path="../../../../../bin/Physics/"/> 3428 <Reference name="OpenSim.Region.Physics.OdePlugin" path="../../../../../bin/Physics/"/>
3429 <Reference name="OpenSim.Tests.Common"/>
3417 <Reference name="Ode.NET" path="../../../../../bin/"/> 3430 <Reference name="Ode.NET" path="../../../../../bin/"/>
3418 <Reference name="nunit.framework" path="../../../../../bin/"/> 3431 <Reference name="nunit.framework" path="../../../../../bin/"/>
3419 <Reference name="log4net" path="../../../../../bin/"/> 3432 <Reference name="log4net" path="../../../../../bin/"/>