aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore2
-rw-r--r--.nant/local.include3
-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/NullRegionData.cs64
-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/CommandConsole.cs10
-rw-r--r--OpenSim/Framework/Console/ConsoleDisplayTable.cs15
-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.cs163
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs34
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs150
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs4
-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.cs45
-rw-r--r--OpenSim/Region/Application/OpenSim.cs37
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs13
-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/Attachments/AttachmentsModule.cs15
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs3
-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/Archiver/InventoryArchiveWriteRequest.cs10
-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.cs67
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs35
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs18
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs317
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs129
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs98
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs13
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs11
-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/Sun/SunModule.cs44
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs2
-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/ISceneCommandsModule.cs43
-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/EventManager.cs13
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs36
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs233
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs62
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs102
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs44
-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/Animations/AnimationsCommandModule.cs215
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.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/MoneyModule/SampleMoneyModule.cs14
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs2
-rw-r--r--OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs227
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs814
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs135
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs153
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs180
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs57
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs1377
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs329
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs397
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs316
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs200
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs347
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs559
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs346
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs81
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs1494
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs957
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs1015
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs208
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs175
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs461
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs267
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs1603
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs280
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs1885
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1598
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs668
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs461
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs27
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1177
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs54
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs352
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs79
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs200
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs571
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs634
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs194
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs853
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs945
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs231
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs183
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs181
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs71
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs1015
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs265
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt290
-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/PhysicsPluginManager.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs11
-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/OdePlugin.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs3
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs3
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSScene.cs4
-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/IScriptApi.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs66
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs194
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs74
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs82
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs52
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs5
-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/Helpers.cs18
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs177
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs29
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs11
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs3
-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.cs11
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs16
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs21
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs126
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs213
-rw-r--r--OpenSim/Region/UserStatistics/WebStatsModule.cs45
-rw-r--r--OpenSim/Server/Base/CommandManager.cs359
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs222
-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/GridService/GridService.cs14
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs2
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs35
-rw-r--r--OpenSim/Services/Interfaces/IOfflineIMService.cs115
-rw-r--r--OpenSim/Services/InventoryService/XInventoryService.cs11
-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
-rw-r--r--TESTING.txt2
-rw-r--r--ThirdPartyLicenses/Bullet-XNA.txt23
-rw-r--r--bin/BulletXNA.dllbin0 -> 614400 bytes
-rw-r--r--bin/BulletXNA.pdbbin0 -> 1875456 bytes
-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/OpenSim.ini.example10
-rw-r--r--bin/OpenSimDefaults.ini56
-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 -> 551424 bytes
-rwxr-xr-xbin/lib32/libBulletSim.sobin1707321 -> 1720142 bytes
-rwxr-xr-xbin/lib64/BulletSim.dllbin699904 -> 700416 bytes
-rwxr-xr-xbin/lib64/libBulletSim.sobin1844228 -> 1858627 bytes
-rw-r--r--doc/README20
-rw-r--r--doc/doxygen.conf1276
-rw-r--r--prebuild.xml64
-rw-r--r--share/Schemas/SceneObjectPart0.xsd166
-rw-r--r--share/Schemas/SceneObjectPart1.xsd8
-rwxr-xr-xshare/php/generateUserFunction.php46
261 files changed, 26474 insertions, 6229 deletions
diff --git a/.gitignore b/.gitignore
index fae7509..91e9be5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,3 +98,5 @@ OpenSim/Region/ScriptEngine/test-results/
98OpenSim/Tests/Common/test-results/ 98OpenSim/Tests/Common/test-results/
99OpenSim/Tests/test-results/ 99OpenSim/Tests/test-results/
100test-results/ 100test-results/
101doc/html
102doc/doxygen.error.log
diff --git a/.nant/local.include b/.nant/local.include
index 5185717..c207944 100644
--- a/.nant/local.include
+++ b/.nant/local.include
@@ -43,10 +43,11 @@
43 <delete dir="${distbindir}/Prebuild"/> 43 <delete dir="${distbindir}/Prebuild"/>
44 <delete dir="${distbindir}/%temp%"/> 44 <delete dir="${distbindir}/%temp%"/>
45 <delete dir="${distbindir}/.nant"/> 45 <delete dir="${distbindir}/.nant"/>
46 <delete dir="${distbindir}/ThirdParty"/>
46 <delete> 47 <delete>
47 <fileset basedir="${distbindir}"> 48 <fileset basedir="${distbindir}">
48 <include name="compile.bat"/> 49 <include name="compile.bat"/>
49 <include name="BUILDING.txt"/> 50 <include name="BUILDING.md"/>
50 <include name="Makefile"/> 51 <include name="Makefile"/>
51 <include name="nant-color"/> 52 <include name="nant-color"/>
52 <include name="OpenSim.*"/> 53 <include name="OpenSim.*"/>
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/NullRegionData.cs b/OpenSim/Data/Null/NullRegionData.cs
index b4d701a..f707d98 100644
--- a/OpenSim/Data/Null/NullRegionData.cs
+++ b/OpenSim/Data/Null/NullRegionData.cs
@@ -113,11 +113,14 @@ namespace OpenSim.Data.Null
113 // Find region data 113 // Find region data
114 List<RegionData> ret = new List<RegionData>(); 114 List<RegionData> ret = new List<RegionData>();
115 115
116 foreach (RegionData r in m_regionData.Values) 116 lock (m_regionData)
117 { 117 {
118// m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower()); 118 foreach (RegionData r in m_regionData.Values)
119 {
120 // m_log.DebugFormat("[NULL REGION DATA]: comparing {0} to {1}", cleanName, r.RegionName.ToLower());
119 if (queryMatch(r.RegionName.ToLower())) 121 if (queryMatch(r.RegionName.ToLower()))
120 ret.Add(r); 122 ret.Add(r);
123 }
121 } 124 }
122 125
123 if (ret.Count > 0) 126 if (ret.Count > 0)
@@ -133,10 +136,13 @@ namespace OpenSim.Data.Null
133 136
134 List<RegionData> ret = new List<RegionData>(); 137 List<RegionData> ret = new List<RegionData>();
135 138
136 foreach (RegionData r in m_regionData.Values) 139 lock (m_regionData)
137 { 140 {
138 if (r.posX == posX && r.posY == posY) 141 foreach (RegionData r in m_regionData.Values)
139 ret.Add(r); 142 {
143 if (r.posX == posX && r.posY == posY)
144 ret.Add(r);
145 }
140 } 146 }
141 147
142 if (ret.Count > 0) 148 if (ret.Count > 0)
@@ -150,8 +156,11 @@ namespace OpenSim.Data.Null
150 if (m_useStaticInstance && Instance != this) 156 if (m_useStaticInstance && Instance != this)
151 return Instance.Get(regionID, scopeID); 157 return Instance.Get(regionID, scopeID);
152 158
153 if (m_regionData.ContainsKey(regionID)) 159 lock (m_regionData)
154 return m_regionData[regionID]; 160 {
161 if (m_regionData.ContainsKey(regionID))
162 return m_regionData[regionID];
163 }
155 164
156 return null; 165 return null;
157 } 166 }
@@ -163,10 +172,13 @@ namespace OpenSim.Data.Null
163 172
164 List<RegionData> ret = new List<RegionData>(); 173 List<RegionData> ret = new List<RegionData>();
165 174
166 foreach (RegionData r in m_regionData.Values) 175 lock (m_regionData)
167 { 176 {
168 if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY) 177 foreach (RegionData r in m_regionData.Values)
169 ret.Add(r); 178 {
179 if (r.posX >= startX && r.posX <= endX && r.posY >= startY && r.posY <= endY)
180 ret.Add(r);
181 }
170 } 182 }
171 183
172 return ret; 184 return ret;
@@ -180,7 +192,10 @@ namespace OpenSim.Data.Null
180// m_log.DebugFormat( 192// m_log.DebugFormat(
181// "[NULL REGION DATA]: Storing region {0} {1}, scope {2}", data.RegionName, data.RegionID, data.ScopeID); 193// "[NULL REGION DATA]: Storing region {0} {1}, scope {2}", data.RegionName, data.RegionID, data.ScopeID);
182 194
183 m_regionData[data.RegionID] = data; 195 lock (m_regionData)
196 {
197 m_regionData[data.RegionID] = data;
198 }
184 199
185 return true; 200 return true;
186 } 201 }
@@ -190,10 +205,13 @@ namespace OpenSim.Data.Null
190 if (m_useStaticInstance && Instance != this) 205 if (m_useStaticInstance && Instance != this)
191 return Instance.SetDataItem(regionID, item, value); 206 return Instance.SetDataItem(regionID, item, value);
192 207
193 if (!m_regionData.ContainsKey(regionID)) 208 lock (m_regionData)
194 return false; 209 {
210 if (!m_regionData.ContainsKey(regionID))
211 return false;
195 212
196 m_regionData[regionID].Data[item] = value; 213 m_regionData[regionID].Data[item] = value;
214 }
197 215
198 return true; 216 return true;
199 } 217 }
@@ -205,10 +223,13 @@ namespace OpenSim.Data.Null
205 223
206// m_log.DebugFormat("[NULL REGION DATA]: Deleting region {0}", regionID); 224// m_log.DebugFormat("[NULL REGION DATA]: Deleting region {0}", regionID);
207 225
208 if (!m_regionData.ContainsKey(regionID)) 226 lock (m_regionData)
209 return false; 227 {
228 if (!m_regionData.ContainsKey(regionID))
229 return false;
210 230
211 m_regionData.Remove(regionID); 231 m_regionData.Remove(regionID);
232 }
212 233
213 return true; 234 return true;
214 } 235 }
@@ -238,10 +259,13 @@ namespace OpenSim.Data.Null
238 259
239 List<RegionData> ret = new List<RegionData>(); 260 List<RegionData> ret = new List<RegionData>();
240 261
241 foreach (RegionData r in m_regionData.Values) 262 lock (m_regionData)
242 { 263 {
243 if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0) 264 foreach (RegionData r in m_regionData.Values)
244 ret.Add(r); 265 {
266 if ((Convert.ToInt32(r.Data["flags"]) & regionFlags) != 0)
267 ret.Add(r);
268 }
245 } 269 }
246 270
247 return ret; 271 return ret;
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/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs
index d703d78..9490013 100644
--- a/OpenSim/Framework/Console/CommandConsole.cs
+++ b/OpenSim/Framework/Console/CommandConsole.cs
@@ -110,10 +110,11 @@ namespace OpenSim.Framework.Console
110 // Remove initial help keyword 110 // Remove initial help keyword
111 helpParts.RemoveAt(0); 111 helpParts.RemoveAt(0);
112 112
113 help.Add(""); // Will become a newline.
114
113 // General help 115 // General help
114 if (helpParts.Count == 0) 116 if (helpParts.Count == 0)
115 { 117 {
116 help.Add(""); // Will become a newline.
117 help.Add(GeneralHelpText); 118 help.Add(GeneralHelpText);
118 help.AddRange(CollectAllCommandsHelp()); 119 help.AddRange(CollectAllCommandsHelp());
119 } 120 }
@@ -129,6 +130,8 @@ namespace OpenSim.Framework.Console
129 help.AddRange(CollectHelp(helpParts)); 130 help.AddRange(CollectHelp(helpParts));
130 } 131 }
131 132
133 help.Add(""); // Will become a newline.
134
132 return help; 135 return help;
133 } 136 }
134 137
@@ -199,14 +202,11 @@ namespace OpenSim.Framework.Console
199 202
200 string descriptiveHelp = commandInfo.descriptive_help; 203 string descriptiveHelp = commandInfo.descriptive_help;
201 204
202 // If we do have some descriptive help then insert a spacing line before and after for readability. 205 // If we do have some descriptive help then insert a spacing line before for readability.
203 if (descriptiveHelp != string.Empty) 206 if (descriptiveHelp != string.Empty)
204 help.Add(string.Empty); 207 help.Add(string.Empty);
205 208
206 help.Add(commandInfo.descriptive_help); 209 help.Add(commandInfo.descriptive_help);
207
208 if (descriptiveHelp != string.Empty)
209 help.Add(string.Empty);
210 } 210 }
211 else 211 else
212 { 212 {
diff --git a/OpenSim/Framework/Console/ConsoleDisplayTable.cs b/OpenSim/Framework/Console/ConsoleDisplayTable.cs
index c620dfe..711a337 100644
--- a/OpenSim/Framework/Console/ConsoleDisplayTable.cs
+++ b/OpenSim/Framework/Console/ConsoleDisplayTable.cs
@@ -56,7 +56,7 @@ namespace OpenSim.Framework.Console
56 public List<ConsoleDisplayTableRow> Rows { get; private set; } 56 public List<ConsoleDisplayTableRow> Rows { get; private set; }
57 57
58 /// <summary> 58 /// <summary>
59 /// Number of spaces to indent the table. 59 /// Number of spaces to indent the whole table.
60 /// </summary> 60 /// </summary>
61 public int Indent { get; set; } 61 public int Indent { get; set; }
62 62
@@ -84,7 +84,7 @@ namespace OpenSim.Framework.Console
84 Columns.Add(new ConsoleDisplayTableColumn(name, width)); 84 Columns.Add(new ConsoleDisplayTableColumn(name, width));
85 } 85 }
86 86
87 public void AddRow(params string[] cells) 87 public void AddRow(params object[] cells)
88 { 88 {
89 Rows.Add(new ConsoleDisplayTableRow(cells)); 89 Rows.Add(new ConsoleDisplayTableRow(cells));
90 } 90 }
@@ -113,7 +113,8 @@ namespace OpenSim.Framework.Console
113 113
114 for (int i = 0; i < Columns.Count; i++) 114 for (int i = 0; i < Columns.Count; i++)
115 { 115 {
116 formatSb.Append(' ', TableSpacing); 116 if (i != 0)
117 formatSb.Append(' ', TableSpacing);
117 118
118 // Can only do left formatting for now 119 // Can only do left formatting for now
119 formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width); 120 formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
@@ -139,16 +140,16 @@ namespace OpenSim.Framework.Console
139 140
140 public struct ConsoleDisplayTableRow 141 public struct ConsoleDisplayTableRow
141 { 142 {
142 public List<string> Cells { get; private set; } 143 public List<object> Cells { get; private set; }
143 144
144 public ConsoleDisplayTableRow(List<string> cells) : this() 145 public ConsoleDisplayTableRow(List<object> cells) : this()
145 { 146 {
146 Cells = cells; 147 Cells = cells;
147 } 148 }
148 149
149 public ConsoleDisplayTableRow(params string[] cells) : this() 150 public ConsoleDisplayTableRow(params object[] cells) : this()
150 { 151 {
151 Cells = new List<string>(cells); 152 Cells = new List<object>(cells);
152 } 153 }
153 } 154 }
154} \ No newline at end of file 155} \ No newline at end of file
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..bfbc480 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -77,6 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer
77 // protected HttpListener m_httpListener; 77 // protected HttpListener m_httpListener;
78 protected CoolHTTPListener m_httpListener2; 78 protected CoolHTTPListener m_httpListener2;
79 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); 79 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
80 protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
80 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); 81 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>();
81 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ 82 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
82 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); 83 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
@@ -217,6 +218,37 @@ namespace OpenSim.Framework.Servers.HttpServer
217 return new List<string>(m_rpcHandlers.Keys); 218 return new List<string>(m_rpcHandlers.Keys);
218 } 219 }
219 220
221 // JsonRPC
222 public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
223 {
224 lock(jsonRpcHandlers)
225 {
226 jsonRpcHandlers.Add(method, handler);
227 }
228 return true;
229 }
230
231 public JsonRPCMethod GetJsonRPCHandler(string method)
232 {
233 lock (jsonRpcHandlers)
234 {
235 if (jsonRpcHandlers.ContainsKey(method))
236 {
237 return jsonRpcHandlers[method];
238 }
239 else
240 {
241 return null;
242 }
243 }
244 }
245
246 public List<string> GetJsonRpcHandlerKeys()
247 {
248 lock (jsonRpcHandlers)
249 return new List<string>(jsonRpcHandlers.Keys);
250 }
251
220 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) 252 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
221 { 253 {
222 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); 254 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
@@ -437,7 +469,7 @@ namespace OpenSim.Framework.Servers.HttpServer
437// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); 469// 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); 470 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
439 471
440 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 472 Culture.SetCurrentCulture();
441 473
442// // This is the REST agent interface. We require an agent to properly identify 474// // 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 475// // itself. If the REST handler recognizes the prefix it will attempt to
@@ -557,10 +589,18 @@ namespace OpenSim.Framework.Servers.HttpServer
557 589
558 buffer = HandleLLSDRequests(request, response); 590 buffer = HandleLLSDRequests(request, response);
559 break; 591 break;
592
593 case "application/json-rpc":
594 if (DebugLevel >= 3)
595 LogIncomingToContentTypeHandler(request);
596
597 buffer = HandleJsonRpcRequests(request, response);
598 break;
560 599
561 case "text/xml": 600 case "text/xml":
562 case "application/xml": 601 case "application/xml":
563 case "application/json": 602 case "application/json":
603
564 default: 604 default:
565 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); 605 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
566 // Point of note.. the DoWeHaveA methods check for an EXACT path 606 // Point of note.. the DoWeHaveA methods check for an EXACT path
@@ -986,6 +1026,74 @@ namespace OpenSim.Framework.Servers.HttpServer
986 return buffer; 1026 return buffer;
987 } 1027 }
988 1028
1029 // JsonRpc (v2.0 only)
1030 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1031 {
1032 Stream requestStream = request.InputStream;
1033 JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
1034 OSDMap jsonRpcRequest = null;
1035
1036 try
1037 {
1038 jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
1039 }
1040 catch (LitJson.JsonException e)
1041 {
1042 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1043 jsonRpcResponse.Error.Message = e.Message;
1044 }
1045
1046 requestStream.Close();
1047
1048 if (jsonRpcRequest != null)
1049 {
1050 if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
1051 {
1052 jsonRpcResponse.JsonRpc = "2.0";
1053
1054 // If we have no id, then it's a "notification"
1055 if (jsonRpcRequest.ContainsKey("id"))
1056 {
1057 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1058 }
1059
1060 string methodname = jsonRpcRequest["method"];
1061 JsonRPCMethod method;
1062
1063 if (jsonRpcHandlers.ContainsKey(methodname))
1064 {
1065 lock(jsonRpcHandlers)
1066 {
1067 jsonRpcHandlers.TryGetValue(methodname, out method);
1068 }
1069
1070 method(jsonRpcRequest, ref jsonRpcResponse);
1071 }
1072 else // Error no hanlder defined for requested method
1073 {
1074 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1075 jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
1076 }
1077 }
1078 else // not json-rpc 2.0 could be v1
1079 {
1080 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1081 jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1082
1083 if (jsonRpcRequest.ContainsKey("id"))
1084 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1085 }
1086 }
1087
1088 response.KeepAlive = true;
1089 string responseData = string.Empty;
1090
1091 responseData = jsonRpcResponse.Serialize();
1092
1093 byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1094 return buffer;
1095 }
1096
989 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) 1097 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
990 { 1098 {
991 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); 1099 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
@@ -1283,59 +1391,6 @@ namespace OpenSim.Framework.Servers.HttpServer
1283 map["login"] = OSD.FromString("false"); 1391 map["login"] = OSD.FromString("false");
1284 return map; 1392 return map;
1285 } 1393 }
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 1394
1340 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) 1395 public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
1341 { 1396 {
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index 0bd3aae..13b5dd3 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -97,6 +97,8 @@ namespace OpenSim.Framework.Servers.HttpServer
97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler); 97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler);
98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); 98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive);
99 99
100 bool AddJsonRPCHandler(string method, JsonRPCMethod handler);
101
100 /// <summary> 102 /// <summary>
101 /// Gets the XML RPC handler for given method name 103 /// Gets the XML RPC handler for given method name
102 /// </summary> 104 /// </summary>
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
new file mode 100644
index 0000000..7334049
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -0,0 +1,34 @@
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.Net;
29using OpenMetaverse.StructuredData;
30
31namespace OpenSim.Framework.Servers.HttpServer
32{
33 public delegate void JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
34}
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
new file mode 100644
index 0000000..2c50587
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
@@ -0,0 +1,150 @@
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.Net;
29using OpenMetaverse.StructuredData;
30
31namespace OpenSim.Framework.Servers.HttpServer
32{
33 public sealed class ErrorCode
34 {
35 private ErrorCode() {}
36
37 public const int ParseError = -32700;
38 public const int InvalidRequest = -32600;
39 public const int MethodNotFound = -32601;
40 public const int InvalidParams = -32602;
41 public const int InternalError = -32604;
42
43 }
44
45 public class JsonRpcError
46 {
47 internal OSDMap Error = new OSDMap();
48
49 public int Code
50 {
51 get
52 {
53 if (Error.ContainsKey("code"))
54 return Error["code"].AsInteger();
55 else
56 return 0;
57 }
58 set
59 {
60 Error["code"] = OSD.FromInteger(value);
61 }
62 }
63
64 public string Message
65 {
66 get
67 {
68 if (Error.ContainsKey("message"))
69 return Error["message"].AsString();
70 else
71 return null;
72 }
73 set
74 {
75 Error["message"] = OSD.FromString(value);
76 }
77 }
78
79 public OSD Data
80 {
81 get; set;
82 }
83 }
84
85 public class JsonRpcResponse
86 {
87 public string JsonRpc
88 {
89 get
90 {
91 return Reply["jsonrpc"].AsString();
92 }
93 set
94 {
95 Reply["jsonrpc"] = OSD.FromString(value);
96 }
97 }
98
99 public string Id
100 {
101 get
102 {
103 return Reply["id"].AsString();
104 }
105 set
106 {
107 Reply["id"] = OSD.FromString(value);
108 }
109 }
110
111 public OSD Result
112 {
113 get; set;
114 }
115
116 public JsonRpcError Error
117 {
118 get; set;
119 }
120
121 public OSDMap Reply = new OSDMap();
122
123 public JsonRpcResponse()
124 {
125 Error = new JsonRpcError();
126 }
127
128 public string Serialize()
129 {
130 if (Result != null)
131 Reply["result"] = Result;
132
133 if (Error.Code != 0)
134 {
135 Reply["error"] = (OSD)Error.Error;
136 }
137
138 string result = string.Empty;
139 try
140 {
141 result = OSDParser.SerializeJsonString(Reply);
142 }
143 catch
144 {
145
146 }
147 return result;
148 }
149 }
150}
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index ae7d515..293887f 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -230,6 +230,10 @@ namespace OpenSim.Framework.Servers
230 List<String> poll = httpServer.GetPollServiceHandlerKeys(); 230 List<String> poll = httpServer.GetPollServiceHandlerKeys();
231 foreach (String s in httpServer.GetHTTPHandlerKeys()) 231 foreach (String s in httpServer.GetHTTPHandlerKeys())
232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); 232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
233
234 handlers.AppendFormat("* JSONRPC:\n");
235 foreach (String s in httpServer.GetJsonRpcHandlerKeys())
236 handlers.AppendFormat("\t{0}\n", s);
233 237
234// handlers.AppendFormat("* Agent:\n"); 238// handlers.AppendFormat("* Agent:\n");
235// foreach (String s in httpServer.GetAgentHandlerKeys()) 239// foreach (String s in httpServer.GetAgentHandlerKeys())
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..c049247 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -299,6 +299,13 @@ namespace OpenSim.Framework
299 x; 299 x;
300 } 300 }
301 301
302 // Inclusive, within range test (true if equal to the endpoints)
303 public static bool InRange<T>(T x, T min, T max)
304 where T : IComparable<T>
305 {
306 return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
307 }
308
302 public static uint GetNextXferID() 309 public static uint GetNextXferID()
303 { 310 {
304 uint id = 0; 311 uint id = 0;
@@ -1652,6 +1659,7 @@ namespace OpenSim.Framework
1652 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1659 throw new InvalidOperationException("SmartThreadPool is already initialized");
1653 1660
1654 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); 1661 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2);
1662 m_ThreadPool.Name = "Util";
1655 } 1663 }
1656 1664
1657 public static int FireAndForgetCount() 1665 public static int FireAndForgetCount()
@@ -1724,7 +1732,7 @@ namespace OpenSim.Framework
1724 break; 1732 break;
1725 case FireAndForgetMethod.SmartThreadPool: 1733 case FireAndForgetMethod.SmartThreadPool:
1726 if (m_ThreadPool == null) 1734 if (m_ThreadPool == null)
1727 m_ThreadPool = new SmartThreadPool(2000, 15, 2); 1735 InitThreadPool(15);
1728 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1736 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
1729 break; 1737 break;
1730 case FireAndForgetMethod.Thread: 1738 case FireAndForgetMethod.Thread:
@@ -1753,12 +1761,16 @@ namespace OpenSim.Framework
1753 StringBuilder sb = new StringBuilder(); 1761 StringBuilder sb = new StringBuilder();
1754 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 1762 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1755 { 1763 {
1756 threadPoolUsed = "SmartThreadPool"; 1764 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
1757 maxThreads = m_ThreadPool.MaxThreads; 1765 if (m_ThreadPool != null)
1758 minThreads = m_ThreadPool.MinThreads; 1766 {
1759 inUseThreads = m_ThreadPool.InUseThreads; 1767 threadPoolUsed = "SmartThreadPool";
1760 allocatedThreads = m_ThreadPool.ActiveThreads; 1768 maxThreads = m_ThreadPool.MaxThreads;
1761 waitingCallbacks = m_ThreadPool.WaitingCallbacks; 1769 minThreads = m_ThreadPool.MinThreads;
1770 inUseThreads = m_ThreadPool.InUseThreads;
1771 allocatedThreads = m_ThreadPool.ActiveThreads;
1772 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1773 }
1762 } 1774 }
1763 else if ( 1775 else if (
1764 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 1776 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
@@ -1863,6 +1875,12 @@ namespace OpenSim.Framework
1863 /// </summary> 1875 /// </summary>
1864 public static void PrintCallStack() 1876 public static void PrintCallStack()
1865 { 1877 {
1878 PrintCallStack(m_log.DebugFormat);
1879 }
1880
1881 public delegate void DebugPrinter(string msg, params Object[] parm);
1882 public static void PrintCallStack(DebugPrinter printer)
1883 {
1866 StackTrace stackTrace = new StackTrace(true); // get call stack 1884 StackTrace stackTrace = new StackTrace(true); // get call stack
1867 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) 1885 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1868 1886
@@ -1870,7 +1888,7 @@ namespace OpenSim.Framework
1870 foreach (StackFrame stackFrame in stackFrames) 1888 foreach (StackFrame stackFrame in stackFrames)
1871 { 1889 {
1872 MethodBase mb = stackFrame.GetMethod(); 1890 MethodBase mb = stackFrame.GetMethod();
1873 m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name 1891 printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1874 } 1892 }
1875 } 1893 }
1876 1894
@@ -2096,5 +2114,16 @@ namespace OpenSim.Framework
2096 return firstName + "." + lastName + " " + "@" + uri.Authority; 2114 return firstName + "." + lastName + " " + "@" + uri.Authority;
2097 } 2115 }
2098 #endregion 2116 #endregion
2117
2118 /// <summary>
2119 /// Escapes the special characters used in "LIKE".
2120 /// </summary>
2121 /// <remarks>
2122 /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz"
2123 /// </remarks>
2124 public static string EscapeForLike(string str)
2125 {
2126 return str.Replace("_", "\\_").Replace("%", "\\%");
2127 }
2099 } 2128 }
2100} 2129}
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 08e4023..e1cff69 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -236,18 +236,6 @@ namespace OpenSim
236 + "If an avatar name is given then only packets from that avatar are logged", 236 + "If an avatar name is given then only packets from that avatar are logged",
237 Debug); 237 Debug);
238 238
239 m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
240
241 m_console.Commands.AddCommand("Debug", false, "debug scene",
242 "debug scene active|collisions|physics|scripting|teleport true|false",
243 "Turn on scene debugging.",
244 "If active is false then main scene update and maintenance loops are suspended.\n"
245 + "If collisions is false then collisions with other objects are turned off.\n"
246 + "If physics is false then all physics objects are non-physical.\n"
247 + "If scripting is false then no scripting operations happen.\n"
248 + "If teleport is true then some extra teleport debug information is logged.",
249 Debug);
250
251 m_console.Commands.AddCommand("General", false, "change region", 239 m_console.Commands.AddCommand("General", false, "change region",
252 "change region <region name>", 240 "change region <region name>",
253 "Change current console region", ChangeSelectedRegion); 241 "Change current console region", ChangeSelectedRegion);
@@ -744,31 +732,6 @@ namespace OpenSim
744 732
745 break; 733 break;
746 734
747 case "scene":
748 if (args.Length == 4)
749 {
750 if (SceneManager.CurrentScene == null)
751 {
752 MainConsole.Instance.Output("Please use 'change region <regioname>' first");
753 }
754 else
755 {
756 string key = args[2];
757 string value = args[3];
758 SceneManager.CurrentScene.SetSceneCoreDebug(
759 new Dictionary<string, string>() { { key, value } });
760
761 MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
762 }
763 }
764 else
765 {
766 MainConsole.Instance.Output(
767 "Usage: debug scene active|scripting|collisions|physics|teleport true|false");
768 }
769
770 break;
771
772 default: 735 default:
773 MainConsole.Instance.Output("Unknown debug command"); 736 MainConsole.Instance.Output("Unknown debug command");
774 break; 737 break;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index b06788b..83347e2 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -105,7 +105,6 @@ namespace OpenSim.Region.ClientStack.Linden
105 private static readonly string m_ResourceCostSelectedPath = "0103/"; 105 private static readonly string m_ResourceCostSelectedPath = "0103/";
106 private static readonly string m_UpdateAgentInformationPath = "0500/"; 106 private static readonly string m_UpdateAgentInformationPath = "0500/";
107 107
108
109 // These are callbacks which will be setup by the scene so that we can update scene data when we 108 // These are callbacks which will be setup by the scene so that we can update scene data when we
110 // receive capability calls 109 // receive capability calls
111 public NewInventoryItem AddNewInventoryItem = null; 110 public NewInventoryItem AddNewInventoryItem = null;
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 0a865ab..6428b86 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -6600,19 +6600,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6600 #endregion 6600 #endregion
6601 6601
6602 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; 6602 AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit;
6603 if (handlerAgentRequestSit != null)
6604 if (!(agentRequestSit.AgentData == null
6605 || agentRequestSit.TargetObject == null
6606 || agentRequestSit.TargetObject.TargetID == null
6607 || agentRequestSit.TargetObject.Offset == null))
6608 {
6609 var sp = m_scene.GetScenePresence(agentRequestSit.AgentData.AgentID);
6610 if (sp == null || sp.ParentID != 0) // ignore packet if agent is already sitting
6611 return true;
6612 6603
6613 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID, 6604 if (handlerAgentRequestSit != null)
6614 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset); 6605 handlerAgentRequestSit(this, agentRequestSit.AgentData.AgentID,
6615 } 6606 agentRequestSit.TargetObject.TargetID, agentRequestSit.TargetObject.Offset);
6616 } 6607 }
6617 return true; 6608 return true;
6618 } 6609 }
@@ -12267,11 +12258,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12267 if (logPacket) 12258 if (logPacket)
12268 m_log.DebugFormat( 12259 m_log.DebugFormat(
12269 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}", 12260 "[CLIENT]: PACKET IN from {0} ({1}) in {2} - {3}",
12270 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); 12261 Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name, packet.Type);
12271 } 12262 }
12272 12263
12273 if (!ProcessPacketMethod(packet)) 12264 if (!ProcessPacketMethod(packet))
12274 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 12265 m_log.WarnFormat(
12266 "[CLIENT]: Unhandled packet {0} from {1} ({2}) in {3}. Ignoring.",
12267 packet.Type, Name, SceneAgent.IsChildAgent ? "child" : "root ", Scene.Name);
12275 } 12268 }
12276 12269
12277 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 12270 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 2aeb4cc..7035e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -204,9 +204,12 @@ namespace OpenMetaverse
204 { 204 {
205 UDPPacketBuffer buf; 205 UDPPacketBuffer buf;
206 206
207 if (UsePools) 207 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
208 buf = Pool.GetObject(); 208 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
209 else 209 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
210// if (UsePools)
211// buf = Pool.GetObject();
212// else
210 buf = new UDPPacketBuffer(); 213 buf = new UDPPacketBuffer();
211 214
212 if (IsRunningInbound) 215 if (IsRunningInbound)
@@ -287,8 +290,8 @@ namespace OpenMetaverse
287 catch (ObjectDisposedException) { } 290 catch (ObjectDisposedException) { }
288 finally 291 finally
289 { 292 {
290 if (UsePools) 293// if (UsePools)
291 Pool.ReturnObject(buffer); 294// Pool.ReturnObject(buffer);
292 295
293 // Synchronous mode waits until the packet callback completes 296 // Synchronous mode waits until the packet callback completes
294 // before starting the receive to fetch another packet 297 // before starting the receive to fetch another packet
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/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index acd156e..6323160 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -722,15 +722,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
722 722
723 if (!silent) 723 if (!silent)
724 { 724 {
725 // Killing it here will cause the client to deselect it 725 if (so.HasPrivateAttachmentPoint)
726 // It then reappears on the avatar, deselected
727 // through the full update below
728 //
729 if (so.IsSelected)
730 {
731 m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId });
732 }
733 else if (so.HasPrivateAttachmentPoint)
734 { 726 {
735// m_log.DebugFormat( 727// m_log.DebugFormat(
736// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", 728// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
@@ -745,7 +737,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
745 }); 737 });
746 } 738 }
747 739
748 so.IsSelected = false; // fudge.... 740 // Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update
741 // will succeed, as that will not update if an attachment is selected.
742 so.IsSelected = false; // fudge....
743
749 so.ScheduleGroupForFullUpdate(); 744 so.ScheduleGroupForFullUpdate();
750 } 745 }
751 746
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 27cf204..cfc7e7e 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -322,6 +322,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
322 322
323 if (asset != null) 323 if (asset != null)
324 { 324 {
325 // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars
326 asset.ID = asset.FullID.ToString();
327
325 asset.Temporary = false; 328 asset.Temporary = false;
326 asset.Local = false; 329 asset.Local = false;
327 m_scene.AssetService.Store(asset); 330 m_scene.AssetService.Store(asset);
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index e21547c..f090e15 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/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index d0e88f6..4c85637 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
124 SaveAssets = true; 124 SaveAssets = true;
125 } 125 }
126 126
127 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) 127 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
128 { 128 {
129 Exception reportedException = null; 129 Exception reportedException = null;
130 bool succeeded = true; 130 bool succeeded = true;
@@ -143,6 +143,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
143 m_saveStream.Close(); 143 m_saveStream.Close();
144 } 144 }
145 145
146 if (timedOut)
147 {
148 succeeded = false;
149 reportedException = new Exception("Loading assets timed out");
150 }
151
146 m_module.TriggerInventoryArchiveSaved( 152 m_module.TriggerInventoryArchiveSaved(
147 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); 153 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException);
148 } 154 }
@@ -350,7 +356,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
350 { 356 {
351 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); 357 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified");
352 358
353 ReceivedAllAssets(new List<UUID>(), new List<UUID>()); 359 ReceivedAllAssets(new List<UUID>(), new List<UUID>(), false);
354 } 360 }
355 } 361 }
356 catch (Exception) 362 catch (Exception)
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..fcfdf7c 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; 574 {
575 575 if (!ResolveGroupUuid(parcel.GroupID))
576 if (!ResolveGroupUuid(parcel.GroupID)) 576 {
577 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
578 parcel.GroupID = UUID.Zero;
579 parcel.IsGroupOwned = false;
580 }
581 }
582 else
577 { 583 {
578 parcel.GroupID = UUID.Zero; 584 if (!ResolveUserUuid(scene, parcel.OwnerID))
579 parcel.IsGroupOwned = false; 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 }
@@ -613,13 +622,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
613 /// <returns></returns> 622 /// <returns></returns>
614 private bool ResolveUserUuid(Scene scene, UUID uuid) 623 private bool ResolveUserUuid(Scene scene, UUID uuid)
615 { 624 {
616 if (!m_validUserUuids.ContainsKey(uuid)) 625 lock (m_validUserUuids)
617 { 626 {
618 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); 627 if (!m_validUserUuids.ContainsKey(uuid))
619 m_validUserUuids.Add(uuid, account != null); 628 {
620 } 629 // Note: we call GetUserAccount() inside the lock because this UserID is likely
630 // to occur many times, and we only want to query the users service once.
631 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
632 m_validUserUuids.Add(uuid, account != null);
633 }
621 634
622 return m_validUserUuids[uuid]; 635 return m_validUserUuids[uuid];
636 }
623 } 637 }
624 638
625 /// <summary> 639 /// <summary>
@@ -632,19 +646,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver
632 if (uuid == UUID.Zero) 646 if (uuid == UUID.Zero)
633 return true; // this means the object has no group 647 return true; // this means the object has no group
634 648
635 if (!m_validGroupUuids.ContainsKey(uuid)) 649 lock (m_validGroupUuids)
636 { 650 {
637 bool exists; 651 if (!m_validGroupUuids.ContainsKey(uuid))
638 652 {
639 if (m_groupsModule == null) 653 bool exists;
640 exists = false; 654 if (m_groupsModule == null)
641 else 655 {
642 exists = (m_groupsModule.GetGroupRecord(uuid) != null); 656 exists = false;
657 }
658 else
659 {
660 // Note: we call GetGroupRecord() inside the lock because this GroupID is likely
661 // to occur many times, and we only want to query the groups service once.
662 exists = (m_groupsModule.GetGroupRecord(uuid) != null);
663 }
664 m_validGroupUuids.Add(uuid, exists);
665 }
643 666
644 m_validGroupUuids.Add(uuid, exists); 667 return m_validGroupUuids[uuid];
645 } 668 }
646
647 return m_validGroupUuids[uuid];
648 } 669 }
649 670
650 /// Load an asset 671 /// Load an asset
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
index d751b1c..367693d 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
@@ -590,21 +587,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
590 } 587 }
591 } 588 }
592 589
593 protected void ReceivedAllAssets( 590 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
594 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
595 { 591 {
596 foreach (UUID uuid in assetsNotFoundUuids) 592 string errorMessage;
593
594 if (timedOut)
597 { 595 {
598 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); 596 errorMessage = "Loading assets timed out";
599 } 597 }
598 else
599 {
600 foreach (UUID uuid in assetsNotFoundUuids)
601 {
602 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
603 }
600 604
601 // m_log.InfoFormat( 605 // m_log.InfoFormat(
602 // "[ARCHIVER]: Received {0} of {1} assets requested", 606 // "[ARCHIVER]: Received {0} of {1} assets requested",
603 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); 607 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
604 608
605 CloseArchive(String.Empty); 609 errorMessage = String.Empty;
610 }
611
612 CloseArchive(errorMessage);
606 } 613 }
607
608 614
609 /// <summary> 615 /// <summary>
610 /// Closes the archive and notifies that we're done. 616 /// Closes the archive and notifies that we're done.
@@ -629,6 +635,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
629 635
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); 636 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 } 637 }
632
633 } 638 }
634} 639}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
index 95d109c..c1ff94d 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
@@ -150,12 +150,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); 150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten);
151 } 151 }
152 152
153 /// <summary>
154 /// Only call this if you need to force a close on the underlying writer.
155 /// </summary>
156 public void ForceClose()
157 {
158 m_archiveWriter.Close();
159 }
160 } 153 }
161} 154}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index e2f8833..715bf51 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
50 /// Method called when all the necessary assets for an archive request have been received. 50 /// Method called when all the necessary assets for an archive request have been received.
51 /// </summary> 51 /// </summary>
52 public delegate void AssetsRequestCallback( 52 public delegate void AssetsRequestCallback(
53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); 53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut);
54 54
55 enum RequestState 55 enum RequestState
56 { 56 {
@@ -148,7 +148,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
148 if (m_repliesRequired == 0) 148 if (m_repliesRequired == 0)
149 { 149 {
150 m_requestState = RequestState.Completed; 150 m_requestState = RequestState.Completed;
151 PerformAssetsRequestCallback(null); 151 PerformAssetsRequestCallback(false);
152 return; 152 return;
153 } 153 }
154 154
@@ -164,7 +164,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
164 164
165 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) 165 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args)
166 { 166 {
167 bool close = true; 167 bool timedOut = true;
168 168
169 try 169 try
170 { 170 {
@@ -174,7 +174,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
174 // the final request came in (assuming that such a thing is possible) 174 // the final request came in (assuming that such a thing is possible)
175 if (m_requestState == RequestState.Completed) 175 if (m_requestState == RequestState.Completed)
176 { 176 {
177 close = false; 177 timedOut = false;
178 return; 178 return;
179 } 179 }
180 180
@@ -223,8 +223,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
223 } 223 }
224 finally 224 finally
225 { 225 {
226 if (close) 226 if (timedOut)
227 m_assetsArchiver.ForceClose(); 227 Util.FireAndForget(PerformAssetsRequestCallback, true);
228 } 228 }
229 } 229 }
230 230
@@ -290,7 +290,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
290 290
291 // We want to stop using the asset cache thread asap 291 // We want to stop using the asset cache thread asap
292 // as we now need to do the work of producing the rest of the archive 292 // as we now need to do the work of producing the rest of the archive
293 Util.FireAndForget(PerformAssetsRequestCallback); 293 Util.FireAndForget(PerformAssetsRequestCallback, false);
294 } 294 }
295 else 295 else
296 { 296 {
@@ -311,9 +311,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
311 { 311 {
312 Culture.SetCurrentCulture(); 312 Culture.SetCurrentCulture();
313 313
314 Boolean timedOut = (Boolean)o;
315
314 try 316 try
315 { 317 {
316 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); 318 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut);
317 } 319 }
318 catch (Exception e) 320 catch (Exception e)
319 { 321 {
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..a5f5749 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)
@@ -76,7 +128,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
76 { 128 {
77 uint sun = 0; 129 uint sun = 0;
78 130
79 if (!Scene.RegionInfo.EstateSettings.UseGlobalTime) 131 if (Scene.RegionInfo.EstateSettings.FixedSun)
80 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; 132 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800;
81 UUID estateOwner; 133 UUID estateOwner;
82 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; 134 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner;
@@ -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
@@ -718,13 +780,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
718 Scene.RegionInfo.RegionSettings.Save(); 780 Scene.RegionInfo.RegionSettings.Save();
719 TriggerRegionInfoChange(); 781 TriggerRegionInfoChange();
720 782
721 Scene.SetSceneCoreDebug( 783 ISceneCommandsModule scm = Scene.RequestModuleInterface<ISceneCommandsModule>();
722 new Dictionary<string, string>() { 784
723 { "scripting", (!disableScripts).ToString() }, 785 if (scm != null)
724 { "collisions", (!disableCollisions).ToString() }, 786 {
725 { "physics", (!disablePhysics).ToString() } 787 scm.SetSceneDebugOptions(
726 } 788 new Dictionary<string, string>() {
727 ); 789 { "scripting", (!disableScripts).ToString() },
790 { "collisions", (!disableCollisions).ToString() },
791 { "physics", (!disablePhysics).ToString() }
792 }
793 );
794 }
728 } 795 }
729 796
730 private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) 797 private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey)
@@ -1066,6 +1133,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1066 { 1133 {
1067 Scene.RegionInfo.EstateSettings.UseGlobalTime = false; 1134 Scene.RegionInfo.EstateSettings.UseGlobalTime = false;
1068 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; 1135 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0;
1136 // Warning: FixedSun should be set to True, otherwise this sun position won't be used.
1069 } 1137 }
1070 1138
1071 if ((parms1 & 0x00000010) != 0) 1139 if ((parms1 & 0x00000010) != 0)
@@ -1118,49 +1186,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
1118 1186
1119 #endregion 1187 #endregion
1120 1188
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 1189 #region Other Functions
1165 1190
1166 public void changeWaterHeight(float height) 1191 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..b4f7d51 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -141,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Land
141 m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy; 141 m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
142 m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy; 142 m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
143 m_scene.EventManager.OnNewClient += EventManagerOnNewClient; 143 m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
144 m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent;
144 m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement; 145 m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
145 m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage; 146 m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
146 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; 147 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
@@ -221,6 +222,11 @@ namespace OpenSim.Region.CoreModules.World.Land
221 } 222 }
222 } 223 }
223 224
225 public void EventMakeChildAgent(ScenePresence avatar)
226 {
227 avatar.currentParcelUUID = UUID.Zero;
228 }
229
224 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) 230 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
225 { 231 {
226 } 232 }
@@ -249,17 +255,15 @@ namespace OpenSim.Region.CoreModules.World.Land
249 newData.LocalID = local_id; 255 newData.LocalID = local_id;
250 ILandObject landobj = null; 256 ILandObject landobj = null;
251 257
258 ILandObject land;
252 lock (m_landList) 259 lock (m_landList)
253 { 260 {
254 if (m_landList.ContainsKey(local_id)) 261 if (m_landList.TryGetValue(local_id, out land))
255 { 262 land.LandData = newData;
256 m_landList[local_id].LandData = newData;
257 landobj = m_landList[local_id];
258// m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]);
259 }
260 } 263 }
261 if(landobj != null) 264
262 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, landobj); 265 if (land != null)
266 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
263 } 267 }
264 268
265 public bool AllowedForcefulBans 269 public bool AllowedForcefulBans
@@ -584,7 +588,7 @@ namespace OpenSim.Region.CoreModules.World.Land
584 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated 588 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
585 // as a random UUID inside LandData initialization 589 // as a random UUID inside LandData initialization
586 if (m_primCountModule != null) 590 if (m_primCountModule != null)
587 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); 591 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
588 592
589 lock (m_landList) 593 lock (m_landList)
590 { 594 {
@@ -621,6 +625,7 @@ namespace OpenSim.Region.CoreModules.World.Land
621 /// <param name="local_id">Land.localID of the peice of land to remove.</param> 625 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
622 public void removeLandObject(int local_id) 626 public void removeLandObject(int local_id)
623 { 627 {
628 ILandObject land;
624 lock (m_landList) 629 lock (m_landList)
625 { 630 {
626 for (int x = 0; x < 64; x++) 631 for (int x = 0; x < 64; x++)
@@ -637,9 +642,11 @@ namespace OpenSim.Region.CoreModules.World.Land
637 } 642 }
638 } 643 }
639 644
640 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); 645 land = m_landList[local_id];
641 m_landList.Remove(local_id); 646 m_landList.Remove(local_id);
642 } 647 }
648
649 m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
643 } 650 }
644 651
645 /// <summary> 652 /// <summary>
@@ -1384,9 +1391,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1384 } 1391 }
1385 1392
1386 for (int i = 0; i < data.Count; i++) 1393 for (int i = 0; i < data.Count; i++)
1387 {
1388 IncomingLandObjectFromStorage(data[i]); 1394 IncomingLandObjectFromStorage(data[i]);
1389 }
1390 } 1395 }
1391 1396
1392 public void IncomingLandObjectFromStorage(LandData data) 1397 public void IncomingLandObjectFromStorage(LandData data)
@@ -1401,25 +1406,72 @@ namespace OpenSim.Region.CoreModules.World.Land
1401 1406
1402 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) 1407 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
1403 { 1408 {
1404 ILandObject selectedParcel = null; 1409 if (localID != -1)
1405 lock (m_landList)
1406 { 1410 {
1407 m_landList.TryGetValue(localID, out selectedParcel); 1411 ILandObject selectedParcel = null;
1412 lock (m_landList)
1413 {
1414 m_landList.TryGetValue(localID, out selectedParcel);
1415 }
1416
1417 if (selectedParcel == null)
1418 return;
1419
1420 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1408 } 1421 }
1422 else
1423 {
1424 if (returnType != 1)
1425 {
1426 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1427 return;
1428 }
1429
1430 // We get here when the user returns objects from the list of Top Colliders or Top Scripts.
1431 // In that case we receive specific object UUID's, but no parcel ID.
1432
1433 Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new Dictionary<UUID, HashSet<SceneObjectGroup>>();
1434
1435 foreach (UUID groupID in taskIDs)
1436 {
1437 SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID);
1438 if (obj != null)
1439 {
1440 if (!returns.ContainsKey(obj.OwnerID))
1441 returns[obj.OwnerID] = new HashSet<SceneObjectGroup>();
1442 returns[obj.OwnerID].Add(obj);
1443 }
1444 else
1445 {
1446 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1447 }
1448 }
1409 1449
1410 if (selectedParcel == null) return; 1450 int num = 0;
1451 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1452 num += objs.Count;
1453 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1411 1454
1412 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); 1455 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1456 {
1457 List<SceneObjectGroup> objs2 = new List<SceneObjectGroup>(objs);
1458 if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2))
1459 {
1460 m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId);
1461 }
1462 else
1463 {
1464 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1465 objs2.Count, objs2[0].OwnerID);
1466 }
1467 }
1468 }
1413 } 1469 }
1414 1470
1415 public void EventManagerOnNoLandDataFromStorage() 1471 public void EventManagerOnNoLandDataFromStorage()
1416 { 1472 {
1417 // called methods already have locks 1473 ResetSimLandObjects();
1418// lock (m_landList) 1474 CreateDefaultParcel();
1419 {
1420 ResetSimLandObjects();
1421 CreateDefaultParcel();
1422 }
1423 } 1475 }
1424 1476
1425 #endregion 1477 #endregion
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index fdac418..07d00c0 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -761,9 +761,10 @@ namespace OpenSim.Region.CoreModules.World.Land
761 int ty = min_y * 4; 761 int ty = min_y * 4;
762 if (ty > ((int)Constants.RegionSize - 1)) 762 if (ty > ((int)Constants.RegionSize - 1))
763 ty = ((int)Constants.RegionSize - 1); 763 ty = ((int)Constants.RegionSize - 1);
764
764 LandData.AABBMin = 765 LandData.AABBMin =
765 new Vector3((float) (min_x * 4), (float) (min_y * 4), 766 new Vector3(
766 (float) m_scene.Heightmap[tx, ty]); 767 (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
767 768
768 tx = max_x * 4; 769 tx = max_x * 4;
769 if (tx > ((int)Constants.RegionSize - 1)) 770 if (tx > ((int)Constants.RegionSize - 1))
@@ -771,9 +772,11 @@ namespace OpenSim.Region.CoreModules.World.Land
771 ty = max_y * 4; 772 ty = max_y * 4;
772 if (ty > ((int)Constants.RegionSize - 1)) 773 if (ty > ((int)Constants.RegionSize - 1))
773 ty = ((int)Constants.RegionSize - 1); 774 ty = ((int)Constants.RegionSize - 1);
774 LandData.AABBMax = 775
775 new Vector3((float) (max_x * 4), (float) (max_y * 4), 776 LandData.AABBMax
776 (float) m_scene.Heightmap[tx, ty]); 777 = new Vector3(
778 (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
779
777 LandData.Area = tempArea; 780 LandData.Area = tempArea;
778 } 781 }
779 782
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index 55b8227..771fdd2 100644
--- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
@@ -490,11 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Land
490 490
491 m_Scene.ForEachSOG(AddObject); 491 m_Scene.ForEachSOG(AddObject);
492 492
493 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); 493 lock (m_PrimCounts)
494 foreach (UUID k in primcountKeys)
495 { 494 {
496 if (!m_OwnerMap.ContainsKey(k)) 495 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys);
497 m_PrimCounts.Remove(k); 496 foreach (UUID k in primcountKeys)
497 {
498 if (!m_OwnerMap.ContainsKey(k))
499 m_PrimCounts.Remove(k);
500 }
498 } 501 }
499 502
500 m_Tainted = false; 503 m_Tainted = false;
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/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
index a321c09..6f344c8 100644
--- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
@@ -252,12 +252,11 @@ namespace OpenSim.Region.CoreModules
252 } 252 }
253 253
254 // TODO: Decouple this, so we can get rid of Linden Hour info 254 // TODO: Decouple this, so we can get rid of Linden Hour info
255 // Update Region infor with new Sun Position and Hour 255 // Update Region with new Sun Vector
256 // set estate settings for region access to sun position 256 // set estate settings for region access to sun position
257 if (receivedEstateToolsSunUpdate) 257 if (receivedEstateToolsSunUpdate)
258 { 258 {
259 m_scene.RegionInfo.RegionSettings.SunVector = Position; 259 m_scene.RegionInfo.RegionSettings.SunVector = Position;
260 m_scene.RegionInfo.RegionSettings.SunPosition = GetCurrentTimeAsLindenSunHour();
261 } 260 }
262 } 261 }
263 262
@@ -395,7 +394,7 @@ namespace OpenSim.Region.CoreModules
395 ready = false; 394 ready = false;
396 395
397 // Remove our hooks 396 // Remove our hooks
398 m_scene.EventManager.OnFrame -= SunUpdate; 397 m_scene.EventManager.OnFrame -= SunUpdate;
399 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; 398 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel;
400 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; 399 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate;
401 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; 400 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour;
@@ -459,26 +458,33 @@ namespace OpenSim.Region.CoreModules
459 SunToClient(avatar.ControllingClient); 458 SunToClient(avatar.ControllingClient);
460 } 459 }
461 460
462 /// <summary> 461 public void EstateToolsSunUpdate(ulong regionHandle)
463 ///
464 /// </summary>
465 /// <param name="regionHandle"></param>
466 /// <param name="FixedTime">Is the sun's position fixed?</param>
467 /// <param name="useEstateTime">Use the Region or Estate Sun hour?</param>
468 /// <param name="FixedSunHour">What hour of the day is the Sun Fixed at?</param>
469 public void EstateToolsSunUpdate(ulong regionHandle, bool FixedSun, bool useEstateTime, float FixedSunHour)
470 { 462 {
471 if (m_scene.RegionInfo.RegionHandle == regionHandle) 463 if (m_scene.RegionInfo.RegionHandle == regionHandle)
472 { 464 {
473 // Must limit the Sun Hour to 0 ... 24 465 float sunFixedHour;
474 while (FixedSunHour > 24.0f) 466 bool fixedSun;
475 FixedSunHour -= 24;
476 467
477 while (FixedSunHour < 0) 468 if (m_scene.RegionInfo.RegionSettings.UseEstateSun)
478 FixedSunHour += 24; 469 {
470 sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition;
471 fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun;
472 }
473 else
474 {
475 sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f;
476 fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun;
477 }
478
479 // Must limit the Sun Hour to 0 ... 24
480 while (sunFixedHour > 24.0f)
481 sunFixedHour -= 24;
479 482
480 m_SunFixedHour = FixedSunHour; 483 while (sunFixedHour < 0)
481 m_SunFixed = FixedSun; 484 sunFixedHour += 24;
485
486 m_SunFixedHour = sunFixedHour;
487 m_SunFixed = fixedSun;
482 488
483 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); 489 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString());
484 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); 490 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString());
@@ -501,7 +507,7 @@ namespace OpenSim.Region.CoreModules
501 { 507 {
502 m_scene.ForEachRootClient(delegate(IClientAPI client) 508 m_scene.ForEachRootClient(delegate(IClientAPI client)
503 { 509 {
504 SunToClient(client); 510 SunToClient(client);
505 }); 511 });
506 } 512 }
507 513
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 33aabe4..4d738a5 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -480,7 +480,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
480 else 480 else
481 { 481 {
482 m_plugineffects[pluginName] = effect; 482 m_plugineffects[pluginName] = effect;
483 m_log.Warn("E ... " + pluginName + " (Replaced)"); 483 m_log.Info("E ... " + pluginName + " (Replaced)");
484 } 484 }
485 } 485 }
486 } 486 }
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/ISceneCommandsModule.cs b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs
new file mode 100644
index 0000000..c5e678b
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ISceneCommandsModule.cs
@@ -0,0 +1,43 @@
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 OpenSim 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;
32using OpenSim.Region.Framework.Scenes;
33
34namespace OpenSim.Region.Framework.Interfaces
35{
36 public interface ISceneCommandsModule
37 {
38 /// <summary>
39 /// Sets the scene debug options.
40 /// </summary>
41 void SetSceneDebugOptions(Dictionary<string, string> options);
42 }
43} \ No newline at end of file
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/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 5b1c9f4..ac5f433 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -755,7 +755,7 @@ namespace OpenSim.Region.Framework.Scenes
755 public event ScriptTimerEvent OnScriptTimerEvent; 755 public event ScriptTimerEvent OnScriptTimerEvent;
756 */ 756 */
757 757
758 public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); 758 public delegate void EstateToolsSunUpdate(ulong regionHandle);
759 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); 759 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
760 760
761 public event EstateToolsSunUpdate OnEstateToolsSunUpdate; 761 public event EstateToolsSunUpdate OnEstateToolsSunUpdate;
@@ -2536,13 +2536,10 @@ namespace OpenSim.Region.Framework.Scenes
2536 } 2536 }
2537 2537
2538 /// <summary> 2538 /// <summary>
2539 /// Updates the system as to how the position of the sun should be handled. 2539 /// Called when the sun's position parameters have changed in the Region and/or Estate
2540 /// </summary> 2540 /// </summary>
2541 /// <param name="regionHandle"></param> 2541 /// <param name="regionHandle">The region that changed</param>
2542 /// <param name="FixedTime">True if the Sun Position is fixed</param> 2542 public void TriggerEstateToolsSunUpdate(ulong regionHandle)
2543 /// <param name="useEstateTime">True if the Estate Settings should be used instead of region</param>
2544 /// <param name="FixedSunHour">The hour 0.0 <= FixedSunHour <= 24.0 at which the sun is fixed at. Sun Hour 0 is sun-rise, when Day/Night ratio is 1:1</param>
2545 public void TriggerEstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float FixedSunHour)
2546 { 2543 {
2547 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate; 2544 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate;
2548 if (handlerEstateToolsSunUpdate != null) 2545 if (handlerEstateToolsSunUpdate != null)
@@ -2551,7 +2548,7 @@ namespace OpenSim.Region.Framework.Scenes
2551 { 2548 {
2552 try 2549 try
2553 { 2550 {
2554 d(regionHandle, FixedTime, useEstateTime, FixedSunHour); 2551 d(regionHandle);
2555 } 2552 }
2556 catch (Exception e) 2553 catch (Exception e)
2557 { 2554 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index c9d1205..9f0a0e2 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 {
@@ -1785,6 +1783,21 @@ namespace OpenSim.Region.Framework.Scenes
1785 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> 1783 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1786 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) 1784 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
1787 { 1785 {
1786 return RezNewScript(
1787 agentID,
1788 itemBase,
1789 "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
1790 }
1791
1792 /// <summary>
1793 /// Rez a new script from nothing with given script text.
1794 /// </summary>
1795 /// <param name="remoteClient"></param>
1796 /// <param name="itemBase">Template item.</param>
1797 /// <param name="scriptText"></param>
1798 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1799 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
1800 {
1788 // The part ID is the folder ID! 1801 // The part ID is the folder ID!
1789 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); 1802 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
1790 if (part == null) 1803 if (part == null)
@@ -1804,9 +1817,14 @@ namespace OpenSim.Region.Framework.Scenes
1804 return null; 1817 return null;
1805 } 1818 }
1806 1819
1807 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1820 AssetBase asset
1808 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"), 1821 = CreateAsset(
1809 agentID); 1822 itemBase.Name,
1823 itemBase.Description,
1824 (sbyte)itemBase.AssetType,
1825 Encoding.ASCII.GetBytes(scriptText),
1826 agentID);
1827
1810 AssetService.Store(asset); 1828 AssetService.Store(asset);
1811 1829
1812 TaskInventoryItem taskItem = new TaskInventoryItem(); 1830 TaskInventoryItem taskItem = new TaskInventoryItem();
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 23006f2..784fc91 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -70,12 +70,77 @@ namespace OpenSim.Region.Framework.Scenes
70 /// <summary> 70 /// <summary>
71 /// Show debug information about teleports. 71 /// Show debug information about teleports.
72 /// </summary> 72 /// </summary>
73 public bool DebugTeleporting { get; private set; } 73 public bool DebugTeleporting { get; set; }
74 74
75 /// <summary> 75 /// <summary>
76 /// Show debug information about the scene loop. 76 /// Show debug information about the scene loop.
77 /// </summary> 77 /// </summary>
78 public bool DebugUpdates { get; private set; } 78 public bool DebugUpdates { get; set; }
79
80 /// <summary>
81 /// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and
82 /// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter).
83 /// </summary>
84 /// <remarks>
85 /// Even if false, the scene will still be saved on clean shutdown.
86 /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels.
87 /// This needs to be fixed.
88 /// </remarks>
89 public bool PeriodicBackup { get; set; }
90
91 /// <summary>
92 /// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even
93 /// if the scene is being shut down for the final time.
94 /// </summary>
95 public bool UseBackup { get; set; }
96
97 /// <summary>
98 /// If false then physical objects are disabled, though collisions will continue as normal.
99 /// </summary>
100 public bool PhysicsEnabled { get; set; }
101
102 /// <summary>
103 /// If false then scripts are not enabled on the smiulator
104 /// </summary>
105 public bool ScriptsEnabled
106 {
107 get { return m_scripts_enabled; }
108 set
109 {
110 if (m_scripts_enabled != value)
111 {
112 if (!value)
113 {
114 m_log.Info("Stopping all Scripts in Scene");
115
116 EntityBase[] entities = Entities.GetEntities();
117 foreach (EntityBase ent in entities)
118 {
119 if (ent is SceneObjectGroup)
120 ((SceneObjectGroup)ent).RemoveScriptInstances(false);
121 }
122 }
123 else
124 {
125 m_log.Info("Starting all Scripts in Scene");
126
127 EntityBase[] entities = Entities.GetEntities();
128 foreach (EntityBase ent in entities)
129 {
130 if (ent is SceneObjectGroup)
131 {
132 SceneObjectGroup sog = (SceneObjectGroup)ent;
133 sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
134 sog.ResumeScripts();
135 }
136 }
137 }
138
139 m_scripts_enabled = value;
140 }
141 }
142 }
143 private bool m_scripts_enabled;
79 144
80 public SynchronizeSceneHandler SynchronizeScene; 145 public SynchronizeSceneHandler SynchronizeScene;
81 146
@@ -284,8 +349,6 @@ namespace OpenSim.Region.Framework.Scenes
284 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 349 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
285 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>(); 350 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
286 351
287 private bool m_physics_enabled = true;
288 private bool m_scripts_enabled = true;
289 private string m_defaultScriptEngine; 352 private string m_defaultScriptEngine;
290 353
291 /// <summary> 354 /// <summary>
@@ -348,7 +411,6 @@ namespace OpenSim.Region.Framework.Scenes
348 411
349 private Timer m_mapGenerationTimer = new Timer(); 412 private Timer m_mapGenerationTimer = new Timer();
350 private bool m_generateMaptiles; 413 private bool m_generateMaptiles;
351 private bool m_useBackup = true;
352 414
353 #endregion Fields 415 #endregion Fields
354 416
@@ -614,11 +676,6 @@ namespace OpenSim.Region.Framework.Scenes
614 get { return m_authenticateHandler; } 676 get { return m_authenticateHandler; }
615 } 677 }
616 678
617 public bool UseBackup
618 {
619 get { return m_useBackup; }
620 }
621
622 // an instance to the physics plugin's Scene object. 679 // an instance to the physics plugin's Scene object.
623 public PhysicsScene PhysicsScene 680 public PhysicsScene PhysicsScene
624 { 681 {
@@ -762,15 +819,22 @@ namespace OpenSim.Region.Framework.Scenes
762 // 819 //
763 // Out of memory 820 // Out of memory
764 // Operating system has killed the plugin 821 // Operating system has killed the plugin
765 m_sceneGraph.UnRecoverableError += RestartNow; 822 m_sceneGraph.UnRecoverableError
823 += () =>
824 {
825 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
826 RestartNow();
827 };
766 828
767 RegisterDefaultSceneEvents(); 829 RegisterDefaultSceneEvents();
768 830
769 DumpAssetsToFile = dumpAssetsToFile; 831 DumpAssetsToFile = dumpAssetsToFile;
770 832
833 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled
834 // better in the future.
771 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; 835 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
772 836
773 m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics; 837 PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics;
774 838
775 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")"; 839 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")";
776 840
@@ -787,8 +851,8 @@ namespace OpenSim.Region.Framework.Scenes
787 StartDisabled = startupConfig.GetBoolean("StartDisabled", false); 851 StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
788 852
789 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); 853 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
790 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup); 854 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
791 if (!m_useBackup) 855 if (!UseBackup)
792 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); 856 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
793 857
794 //Animation states 858 //Animation states
@@ -965,6 +1029,10 @@ namespace OpenSim.Region.Framework.Scenes
965 { 1029 {
966 PhysicalPrims = true; 1030 PhysicalPrims = true;
967 CollidablePrims = true; 1031 CollidablePrims = true;
1032 PhysicsEnabled = true;
1033
1034 PeriodicBackup = true;
1035 UseBackup = true;
968 1036
969 BordersLocked = true; 1037 BordersLocked = true;
970 Border northBorder = new Border(); 1038 Border northBorder = new Border();
@@ -1207,83 +1275,6 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1275 }
1208 } 1276 }
1209 1277
1210 public void SetSceneCoreDebug(Dictionary<string, string> options)
1211 {
1212 if (options.ContainsKey("active"))
1213 {
1214 bool active;
1215
1216 if (bool.TryParse(options["active"], out active))
1217 Active = active;
1218 }
1219
1220 if (options.ContainsKey("scripting"))
1221 {
1222 bool enableScripts = true;
1223 if (bool.TryParse(options["scripting"], out enableScripts) && m_scripts_enabled != enableScripts)
1224 {
1225 if (!enableScripts)
1226 {
1227 m_log.Info("Stopping all Scripts in Scene");
1228
1229 EntityBase[] entities = Entities.GetEntities();
1230 foreach (EntityBase ent in entities)
1231 {
1232 if (ent is SceneObjectGroup)
1233 ((SceneObjectGroup)ent).RemoveScriptInstances(false);
1234 }
1235 }
1236 else
1237 {
1238 m_log.Info("Starting all Scripts in Scene");
1239
1240 EntityBase[] entities = Entities.GetEntities();
1241 foreach (EntityBase ent in entities)
1242 {
1243 if (ent is SceneObjectGroup)
1244 {
1245 SceneObjectGroup sog = (SceneObjectGroup)ent;
1246 sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
1247 sog.ResumeScripts();
1248 }
1249 }
1250 }
1251
1252 m_scripts_enabled = enableScripts;
1253 }
1254 }
1255
1256 if (options.ContainsKey("physics"))
1257 {
1258 bool enablePhysics;
1259 if (bool.TryParse(options["physics"], out enablePhysics))
1260 m_physics_enabled = enablePhysics;
1261 }
1262
1263// if (options.ContainsKey("collisions"))
1264// {
1265// // TODO: Implement. If false, should stop objects colliding, though possibly should still allow
1266// // the avatar themselves to collide with the ground.
1267// }
1268
1269 if (options.ContainsKey("teleport"))
1270 {
1271 bool enableTeleportDebugging;
1272 if (bool.TryParse(options["teleport"], out enableTeleportDebugging))
1273 DebugTeleporting = enableTeleportDebugging;
1274 }
1275
1276 if (options.ContainsKey("updates"))
1277 {
1278 bool enableUpdateDebugging;
1279 if (bool.TryParse(options["updates"], out enableUpdateDebugging))
1280 {
1281 DebugUpdates = enableUpdateDebugging;
1282 GcNotify.Enabled = DebugUpdates;
1283 }
1284 }
1285 }
1286
1287 public int GetInaccurateNeighborCount() 1278 public int GetInaccurateNeighborCount()
1288 { 1279 {
1289 return m_neighbours.Count; 1280 return m_neighbours.Count;
@@ -1332,16 +1323,7 @@ namespace OpenSim.Region.Framework.Scenes
1332 1323
1333 m_log.Debug("[SCENE]: Persisting changed objects"); 1324 m_log.Debug("[SCENE]: Persisting changed objects");
1334 1325
1335 EntityBase[] entities = GetEntities(); 1326 Backup(false);
1336 foreach (EntityBase entity in entities)
1337 {
1338 if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged)
1339 {
1340 ((SceneObjectGroup)entity).ProcessBackup(SimulationDataService, false);
1341 }
1342 }
1343
1344 m_log.Debug("[SCENE]: Graph close");
1345 m_sceneGraph.Close(); 1327 m_sceneGraph.Close();
1346 1328
1347 if (!GridService.DeregisterRegion(RegionInfo.RegionID)) 1329 if (!GridService.DeregisterRegion(RegionInfo.RegionID))
@@ -1568,7 +1550,7 @@ namespace OpenSim.Region.Framework.Scenes
1568 } 1550 }
1569 1551
1570 tmpMS = Util.EnvironmentTickCount(); 1552 tmpMS = Util.EnvironmentTickCount();
1571 if ((Frame % m_update_physics == 0) && m_physics_enabled) 1553 if (PhysicsEnabled && Frame % m_update_physics == 0)
1572 m_sceneGraph.UpdatePreparePhysics(); 1554 m_sceneGraph.UpdatePreparePhysics();
1573 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); 1555 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
1574 1556
@@ -1583,7 +1565,7 @@ namespace OpenSim.Region.Framework.Scenes
1583 tmpMS = Util.EnvironmentTickCount(); 1565 tmpMS = Util.EnvironmentTickCount();
1584 if (Frame % m_update_physics == 0) 1566 if (Frame % m_update_physics == 0)
1585 { 1567 {
1586 if (m_physics_enabled) 1568 if (PhysicsEnabled)
1587 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); 1569 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
1588 1570
1589 if (SynchronizeScene != null) 1571 if (SynchronizeScene != null)
@@ -1625,7 +1607,7 @@ namespace OpenSim.Region.Framework.Scenes
1625 eventMS = Util.EnvironmentTickCountSubtract(tmpMS); 1607 eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
1626 } 1608 }
1627 1609
1628 if (Frame % m_update_backup == 0) 1610 if (PeriodicBackup && Frame % m_update_backup == 0)
1629 { 1611 {
1630 tmpMS = Util.EnvironmentTickCount(); 1612 tmpMS = Util.EnvironmentTickCount();
1631 UpdateStorageBackup(); 1613 UpdateStorageBackup();
@@ -5615,33 +5597,7 @@ Environment.Exit(1);
5615 5597
5616 public void TriggerEstateSunUpdate() 5598 public void TriggerEstateSunUpdate()
5617 { 5599 {
5618 float sun; 5600 EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
5619 if (RegionInfo.RegionSettings.UseEstateSun)
5620 {
5621 sun = (float)RegionInfo.EstateSettings.SunPosition;
5622 if (RegionInfo.EstateSettings.UseGlobalTime)
5623 {
5624 sun = EventManager.GetCurrentTimeAsSunLindenHour() - 6.0f;
5625 }
5626
5627 //
5628 EventManager.TriggerEstateToolsSunUpdate(
5629 RegionInfo.RegionHandle,
5630 RegionInfo.EstateSettings.FixedSun,
5631 RegionInfo.RegionSettings.UseEstateSun,
5632 sun);
5633 }
5634 else
5635 {
5636 // Use the Sun Position from the Region Settings
5637 sun = (float)RegionInfo.RegionSettings.SunPosition - 6.0f;
5638
5639 EventManager.TriggerEstateToolsSunUpdate(
5640 RegionInfo.RegionHandle,
5641 RegionInfo.RegionSettings.FixedSun,
5642 RegionInfo.RegionSettings.UseEstateSun,
5643 sun);
5644 }
5645 } 5601 }
5646 5602
5647 private void HandleReloadEstate(string module, string[] cmd) 5603 private void HandleReloadEstate(string module, string[] cmd)
@@ -6037,10 +5993,17 @@ Environment.Exit(1);
6037 GC.Collect(); 5993 GC.Collect();
6038 } 5994 }
6039 5995
6040 // Wrappers to get physics modules retrieve assets. Has to be done this way 5996 /// <summary>
6041 // because we can't assign the asset service to physics directly - at the 5997 /// Wrappers to get physics modules retrieve assets.
6042 // time physics are instantiated it's not registered but it will be by 5998 /// </summary>
6043 // the time the first prim exists. 5999 /// <remarks>
6000 /// Has to be done this way
6001 /// because we can't assign the asset service to physics directly - at the
6002 /// time physics are instantiated it's not registered but it will be by
6003 /// the time the first prim exists.
6004 /// </remarks>
6005 /// <param name="assetID"></param>
6006 /// <param name="callback"></param>
6044 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) 6007 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
6045 { 6008 {
6046 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); 6009 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index b008e66..dd8541c 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -101,6 +101,15 @@ namespace OpenSim.Region.Framework.Scenes
101 /// </summary> 101 /// </summary>
102 public partial class SceneObjectGroup : EntityBase, ISceneObject 102 public partial class SceneObjectGroup : EntityBase, ISceneObject
103 { 103 {
104 // Axis selection bitmask used by SetAxisRotation()
105 // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
106 public enum axisSelect : int
107 {
108 STATUS_ROTATE_X = 0x002,
109 STATUS_ROTATE_Y = 0x004,
110 STATUS_ROTATE_Z = 0x008,
111 }
112
104 // private PrimCountTaintedDelegate handlerPrimCountTainted = null; 113 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
105 114
106 /// <summary> 115 /// <summary>
@@ -502,11 +511,19 @@ namespace OpenSim.Region.Framework.Scenes
502 511
503 if (Scene != null) 512 if (Scene != null)
504 { 513 {
505 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 514 if (
506 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 515 // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E)
507 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 516 // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
508 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W) 517 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N)
509 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S)) 518 // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
519 // Experimental change for better border crossings.
520 // The commented out original lines above would, it seems, trigger
521 // a border crossing a little early or late depending on which
522 // direction the object was moving.
523 (Scene.TestBorderCross(val, Cardinals.E)
524 || Scene.TestBorderCross(val, Cardinals.W)
525 || Scene.TestBorderCross(val, Cardinals.N)
526 || Scene.TestBorderCross(val, Cardinals.S))
510 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 527 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
511 { 528 {
512 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 529 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
@@ -925,6 +942,18 @@ namespace OpenSim.Region.Framework.Scenes
925 /// </remarks> 942 /// </remarks>
926 public UUID FromFolderID { get; set; } 943 public UUID FromFolderID { get; set; }
927 944
945 /// <summary>
946 /// IDs of all avatars sat on this scene object.
947 /// </summary>
948 /// <remarks>
949 /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
950 /// This must be locked before it is read or written.
951 /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
952 /// No avatar should appear more than once in this list.
953 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
954 /// </remarks>
955 protected internal List<UUID> m_sittingAvatars = new List<UUID>();
956
928 #endregion 957 #endregion
929 958
930// ~SceneObjectGroup() 959// ~SceneObjectGroup()
@@ -4493,17 +4522,28 @@ namespace OpenSim.Region.Framework.Scenes
4493 } 4522 }
4494 4523
4495 /// <summary> 4524 /// <summary>
4525 /// Get a copy of the list of sitting avatars on all prims of this object.
4526 /// </summary>
4527 /// <remarks>
4528 /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
4529 /// down after it move one place down the list.
4530 /// </remarks>
4531 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
4532 public List<UUID> GetSittingAvatars()
4533 {
4534 lock (m_sittingAvatars)
4535 return new List<UUID>(m_sittingAvatars);
4536 }
4537
4538 /// <summary>
4496 /// Gets the number of sitting avatars. 4539 /// Gets the number of sitting avatars.
4497 /// </summary> 4540 /// </summary>
4498 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> 4541 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4499 /// <returns></returns> 4542 /// <returns></returns>
4500 public int GetSittingAvatarsCount() 4543 public int GetSittingAvatarsCount()
4501 { 4544 {
4502 int count = 0; 4545 lock (m_sittingAvatars)
4503 4546 return m_sittingAvatars.Count;
4504 Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount());
4505
4506 return count;
4507 } 4547 }
4508 4548
4509 public override string ToString() 4549 public override string ToString()
@@ -4512,7 +4552,7 @@ namespace OpenSim.Region.Framework.Scenes
4512 } 4552 }
4513 4553
4514 #region ISceneObject 4554 #region ISceneObject
4515 4555
4516 public virtual ISceneObject CloneForNewScene() 4556 public virtual ISceneObject CloneForNewScene()
4517 { 4557 {
4518 SceneObjectGroup sog = Copy(false); 4558 SceneObjectGroup sog = Copy(false);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index ff4ae85..b59ba68 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1342,7 +1342,7 @@ namespace OpenSim.Region.Framework.Scenes
1342 public UUID SitTargetAvatar { get; set; } 1342 public UUID SitTargetAvatar { get; set; }
1343 1343
1344 /// <summary> 1344 /// <summary>
1345 /// IDs of all avatars start on this object part. 1345 /// IDs of all avatars sat on this part.
1346 /// </summary> 1346 /// </summary>
1347 /// <remarks> 1347 /// <remarks>
1348 /// We need to track this so that we can stop sat upon prims from being attached. 1348 /// We need to track this so that we can stop sat upon prims from being attached.
@@ -2431,11 +2431,11 @@ namespace OpenSim.Region.Framework.Scenes
2431 public int GetAxisRotation(int axis) 2431 public int GetAxisRotation(int axis)
2432 { 2432 {
2433 //Cannot use ScriptBaseClass constants as no referance to it currently. 2433 //Cannot use ScriptBaseClass constants as no referance to it currently.
2434 if (axis == 2)//STATUS_ROTATE_X 2434 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
2435 return STATUS_ROTATE_X; 2435 return STATUS_ROTATE_X;
2436 if (axis == 4)//STATUS_ROTATE_Y 2436 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
2437 return STATUS_ROTATE_Y; 2437 return STATUS_ROTATE_Y;
2438 if (axis == 8)//STATUS_ROTATE_Z 2438 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
2439 return STATUS_ROTATE_Z; 2439 return STATUS_ROTATE_Z;
2440 2440
2441 return 0; 2441 return 0;
@@ -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()
@@ -3322,13 +3325,13 @@ namespace OpenSim.Region.Framework.Scenes
3322 ParentGroup.SetAxisRotation(axis, rotate); 3325 ParentGroup.SetAxisRotation(axis, rotate);
3323 3326
3324 //Cannot use ScriptBaseClass constants as no referance to it currently. 3327 //Cannot use ScriptBaseClass constants as no referance to it currently.
3325 if (axis == 2)//STATUS_ROTATE_X 3328 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
3326 STATUS_ROTATE_X = rotate; 3329 STATUS_ROTATE_X = rotate;
3327 3330
3328 if (axis == 4)//STATUS_ROTATE_Y 3331 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
3329 STATUS_ROTATE_Y = rotate; 3332 STATUS_ROTATE_Y = rotate;
3330 3333
3331 if (axis == 8)//STATUS_ROTATE_Z 3334 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
3332 STATUS_ROTATE_Z = rotate; 3335 STATUS_ROTATE_Z = rotate;
3333 } 3336 }
3334 3337
@@ -4558,7 +4561,7 @@ namespace OpenSim.Region.Framework.Scenes
4558 if (ParentGroup.RootPart == this) 4561 if (ParentGroup.RootPart == this)
4559 AngularVelocity = new Vector3(0, 0, 0); 4562 AngularVelocity = new Vector3(0, 0, 0);
4560 } 4563 }
4561 else 4564 else if (SetVD != wasVD)
4562 { 4565 {
4563 if (ParentGroup.Scene.CollidablePrims) 4566 if (ParentGroup.Scene.CollidablePrims)
4564 { 4567 {
@@ -4646,9 +4649,9 @@ namespace OpenSim.Region.Framework.Scenes
4646 PhysicsShapeType, 4649 PhysicsShapeType,
4647 m_localId); 4650 m_localId);
4648 } 4651 }
4649 catch (Exception ex) 4652 catch (Exception e)
4650 { 4653 {
4651 m_log.ErrorFormat("[SCENE]: AddToPhysics object {0} failed: {1}", m_uuid, ex.Message); 4654 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom. e={1}", m_uuid, e);
4652 pa = null; 4655 pa = null;
4653 } 4656 }
4654 4657
@@ -5202,18 +5205,22 @@ namespace OpenSim.Region.Framework.Scenes
5202 /// <param name='avatarId'></param> 5205 /// <param name='avatarId'></param>
5203 protected internal bool AddSittingAvatar(UUID avatarId) 5206 protected internal bool AddSittingAvatar(UUID avatarId)
5204 { 5207 {
5205 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) 5208 lock (ParentGroup.m_sittingAvatars)
5206 SitTargetAvatar = avatarId; 5209 {
5210 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
5211 SitTargetAvatar = avatarId;
5207 5212
5208 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5213 if (m_sittingAvatars == null)
5214 m_sittingAvatars = new HashSet<UUID>();
5209 5215
5210 if (sittingAvatars == null) 5216 if (m_sittingAvatars.Add(avatarId))
5211 sittingAvatars = new HashSet<UUID>(); 5217 {
5218 ParentGroup.m_sittingAvatars.Add(avatarId);
5212 5219
5213 lock (sittingAvatars) 5220 return true;
5214 { 5221 }
5215 m_sittingAvatars = sittingAvatars; 5222
5216 return m_sittingAvatars.Add(avatarId); 5223 return false;
5217 } 5224 }
5218 } 5225 }
5219 5226
@@ -5227,27 +5234,26 @@ namespace OpenSim.Region.Framework.Scenes
5227 /// <param name='avatarId'></param> 5234 /// <param name='avatarId'></param>
5228 protected internal bool RemoveSittingAvatar(UUID avatarId) 5235 protected internal bool RemoveSittingAvatar(UUID avatarId)
5229 { 5236 {
5230 if (SitTargetAvatar == avatarId) 5237 lock (ParentGroup.m_sittingAvatars)
5231 SitTargetAvatar = UUID.Zero; 5238 {
5232 5239 if (SitTargetAvatar == avatarId)
5233 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5240 SitTargetAvatar = UUID.Zero;
5234 5241
5235 // This can occur under a race condition where another thread 5242 if (m_sittingAvatars == null)
5236 if (sittingAvatars == null) 5243 return false;
5237 return false;
5238 5244
5239 lock (sittingAvatars) 5245 if (m_sittingAvatars.Remove(avatarId))
5240 {
5241 if (sittingAvatars.Remove(avatarId))
5242 { 5246 {
5243 if (sittingAvatars.Count == 0) 5247 if (m_sittingAvatars.Count == 0)
5244 m_sittingAvatars = null; 5248 m_sittingAvatars = null;
5245 5249
5250 ParentGroup.m_sittingAvatars.Remove(avatarId);
5251
5246 return true; 5252 return true;
5247 } 5253 }
5248 }
5249 5254
5250 return false; 5255 return false;
5256 }
5251 } 5257 }
5252 5258
5253 /// <summary> 5259 /// <summary>
@@ -5257,16 +5263,12 @@ namespace OpenSim.Region.Framework.Scenes
5257 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> 5263 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
5258 public HashSet<UUID> GetSittingAvatars() 5264 public HashSet<UUID> GetSittingAvatars()
5259 { 5265 {
5260 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5266 lock (ParentGroup.m_sittingAvatars)
5261
5262 if (sittingAvatars == null)
5263 {
5264 return null;
5265 }
5266 else
5267 { 5267 {
5268 lock (sittingAvatars) 5268 if (m_sittingAvatars == null)
5269 return new HashSet<UUID>(sittingAvatars); 5269 return null;
5270 else
5271 return new HashSet<UUID>(m_sittingAvatars);
5270 } 5272 }
5271 } 5273 }
5272 5274
@@ -5277,13 +5279,13 @@ namespace OpenSim.Region.Framework.Scenes
5277 /// <returns></returns> 5279 /// <returns></returns>
5278 public int GetSittingAvatarsCount() 5280 public int GetSittingAvatarsCount()
5279 { 5281 {
5280 HashSet<UUID> sittingAvatars = m_sittingAvatars; 5282 lock (ParentGroup.m_sittingAvatars)
5281 5283 {
5282 if (sittingAvatars == null) 5284 if (m_sittingAvatars == null)
5283 return 0; 5285 return 0;
5284 5286 else
5285 lock (sittingAvatars) 5287 return m_sittingAvatars.Count;
5286 return sittingAvatars.Count; 5288 }
5287 } 5289 }
5288 } 5290 }
5289} 5291}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index a9195f7..c2ff110 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; }
@@ -591,18 +589,18 @@ namespace OpenSim.Region.Framework.Scenes
591 set 589 set
592 { 590 {
593 m_bodyRot = value; 591 m_bodyRot = value;
594 // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
595 if (PhysicsActor != null) 592 if (PhysicsActor != null)
596 { 593 {
597 try 594 try
598 { 595 {
599 PhysicsActor.Orientation = value; 596 PhysicsActor.Orientation = m_bodyRot;
600 } 597 }
601 catch (Exception e) 598 catch (Exception e)
602 { 599 {
603 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message); 600 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message);
604 } 601 }
605 } 602 }
603// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
606 } 604 }
607 } 605 }
608 606
@@ -2199,28 +2197,17 @@ namespace OpenSim.Region.Framework.Scenes
2199 2197
2200 if (ParentID != 0) 2198 if (ParentID != 0)
2201 { 2199 {
2200 var targetPart = m_scene.GetSceneObjectPart(targetID);
2201 if (targetPart != null && targetPart.LocalId == ParentID)
2202 return; // already sitting here, ignore
2203
2202 StandUp(); 2204 StandUp();
2203 } 2205 }
2204 2206
2205// if (!String.IsNullOrEmpty(sitAnimation))
2206// {
2207// m_nextSitAnimation = sitAnimation;
2208// }
2209// else
2210// {
2211 m_nextSitAnimation = "SIT";
2212// }
2213
2214 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
2215 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 2207 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2216 2208
2217 if (part != null) 2209 if (part != null)
2218 { 2210 {
2219 if (!String.IsNullOrEmpty(part.SitAnimation))
2220 {
2221 m_nextSitAnimation = part.SitAnimation;
2222 }
2223
2224 m_requestedSitTargetID = part.LocalId; 2211 m_requestedSitTargetID = part.LocalId;
2225 m_requestedSitTargetUUID = targetID; 2212 m_requestedSitTargetUUID = targetID;
2226 2213
@@ -2341,18 +2328,6 @@ namespace OpenSim.Region.Framework.Scenes
2341 2328
2342 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) 2329 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2343 { 2330 {
2344 if (!String.IsNullOrEmpty(m_nextSitAnimation))
2345 {
2346 HandleAgentSit(remoteClient, agentID, m_nextSitAnimation);
2347 }
2348 else
2349 {
2350 HandleAgentSit(remoteClient, agentID, "SIT");
2351 }
2352 }
2353
2354 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation)
2355 {
2356 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 2331 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2357 2332
2358 if (part != null) 2333 if (part != null)
@@ -2425,7 +2400,12 @@ namespace OpenSim.Region.Framework.Scenes
2425 2400
2426 Velocity = Vector3.Zero; 2401 Velocity = Vector3.Zero;
2427 RemoveFromPhysicalScene(); 2402 RemoveFromPhysicalScene();
2428 2403
2404 String sitAnimation = "SIT";
2405 if (!String.IsNullOrEmpty(part.SitAnimation))
2406 {
2407 sitAnimation = part.SitAnimation;
2408 }
2429 Animator.TrySetMovementAnimation(sitAnimation); 2409 Animator.TrySetMovementAnimation(sitAnimation);
2430 SendAvatarDataToAllAgents(); 2410 SendAvatarDataToAllAgents();
2431 } 2411 }
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/Animations/AnimationsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs
new file mode 100644
index 0000000..e951d9e
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Animations/AnimationsCommandModule.cs
@@ -0,0 +1,215 @@
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 System.Text;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Console;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Animation;
44using OpenSim.Services.Interfaces;
45
46namespace OpenSim.Region.OptionalModules.Avatar.Animations
47{
48 /// <summary>
49 /// A module that just holds commands for inspecting avatar animations.
50 /// </summary>
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")]
52 public class AnimationsCommandModule : ISharedRegionModule
53 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private List<Scene> m_scenes = new List<Scene>();
57
58 public string Name { get { return "Animations Command Module"; } }
59
60 public Type ReplaceableInterface { get { return null; } }
61
62 public void Initialise(IConfigSource source)
63 {
64// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE");
65 }
66
67 public void PostInitialise()
68 {
69// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE");
70 }
71
72 public void Close()
73 {
74// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE");
75 }
76
77 public void AddRegion(Scene scene)
78 {
79// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
80 }
81
82 public void RemoveRegion(Scene scene)
83 {
84// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
85
86 lock (m_scenes)
87 m_scenes.Remove(scene);
88 }
89
90 public void RegionLoaded(Scene scene)
91 {
92// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
93
94 lock (m_scenes)
95 m_scenes.Add(scene);
96
97 scene.AddCommand(
98 "Users", this, "show animations",
99 "show animations [<first-name> <last-name>]",
100 "Show animation information for avatars in this simulator.",
101 "If no name is supplied then information for all avatars is shown.\n"
102 + "Please note that for inventory animations, the animation name is the name under which the animation was originally uploaded\n"
103 + ", which is not necessarily the current inventory name.",
104 HandleShowAnimationsCommand);
105 }
106
107 protected void HandleShowAnimationsCommand(string module, string[] cmd)
108 {
109 if (cmd.Length != 2 && cmd.Length < 4)
110 {
111 MainConsole.Instance.OutputFormat("Usage: show animations [<first-name> <last-name>]");
112 return;
113 }
114
115 bool targetNameSupplied = false;
116 string optionalTargetFirstName = null;
117 string optionalTargetLastName = null;
118
119 if (cmd.Length >= 4)
120 {
121 targetNameSupplied = true;
122 optionalTargetFirstName = cmd[2];
123 optionalTargetLastName = cmd[3];
124 }
125
126 StringBuilder sb = new StringBuilder();
127
128 lock (m_scenes)
129 {
130 foreach (Scene scene in m_scenes)
131 {
132 if (targetNameSupplied)
133 {
134 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
135 if (sp != null && !sp.IsChildAgent)
136 GetAttachmentsReport(sp, sb);
137 }
138 else
139 {
140 scene.ForEachRootScenePresence(sp => GetAttachmentsReport(sp, sb));
141 }
142 }
143 }
144
145 MainConsole.Instance.Output(sb.ToString());
146 }
147
148 private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb)
149 {
150 sb.AppendFormat("Animations for {0}\n", sp.Name);
151
152 ConsoleDisplayList cdl = new ConsoleDisplayList() { Indent = 2 };
153 ScenePresenceAnimator spa = sp.Animator;
154 AnimationSet anims = sp.Animator.Animations;
155
156 string cma = spa.CurrentMovementAnimation;
157 cdl.AddRow(
158 "Current movement anim",
159 string.Format("{0}, {1}", DefaultAvatarAnimations.GetDefaultAnimation(cma), cma));
160
161 UUID defaultAnimId = anims.DefaultAnimation.AnimID;
162 cdl.AddRow(
163 "Default anim",
164 string.Format("{0}, {1}", defaultAnimId, GetAnimName(sp.Scene.AssetService, defaultAnimId)));
165
166 UUID implicitDefaultAnimId = anims.ImplicitDefaultAnimation.AnimID;
167 cdl.AddRow(
168 "Implicit default anim",
169 string.Format("{0}, {1}", implicitDefaultAnimId, GetAnimName(sp.Scene.AssetService, implicitDefaultAnimId)));
170
171 cdl.AddToStringBuilder(sb);
172
173 ConsoleDisplayTable cdt = new ConsoleDisplayTable() { Indent = 2 };
174 cdt.AddColumn("Animation ID", 36);
175 cdt.AddColumn("Name", 20);
176 cdt.AddColumn("Seq", 3);
177 cdt.AddColumn("Object ID", 36);
178
179 UUID[] animIds;
180 int[] sequenceNumbers;
181 UUID[] objectIds;
182
183 sp.Animator.Animations.GetArrays(out animIds, out sequenceNumbers, out objectIds);
184
185 for (int i = 0; i < animIds.Length; i++)
186 {
187 UUID animId = animIds[i];
188 string animName = GetAnimName(sp.Scene.AssetService, animId);
189 int seq = sequenceNumbers[i];
190 UUID objectId = objectIds[i];
191
192 cdt.AddRow(animId, animName, seq, objectId);
193 }
194
195 cdt.AddToStringBuilder(sb);
196 sb.Append("\n");
197 }
198
199 private string GetAnimName(IAssetService assetService, UUID animId)
200 {
201 string animName;
202
203 if (!DefaultAvatarAnimations.AnimsNames.TryGetValue(animId, out animName))
204 {
205 AssetMetadata amd = assetService.GetMetadata(animId.ToString());
206 if (amd != null)
207 animName = amd.Name;
208 else
209 animName = "Unknown";
210 }
211
212 return animName;
213 }
214 }
215} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index 68bcb4a..d97e3b3 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -97,6 +97,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
97 "Users", this, "attachments show", 97 "Users", this, "attachments show",
98 "attachments show [<first-name> <last-name>]", 98 "attachments show [<first-name> <last-name>]",
99 "Show attachment information for avatars in this simulator.", 99 "Show attachment information for avatars in this simulator.",
100 "If no name is supplied then information for all avatars is shown.",
100 HandleShowAttachmentsCommand); 101 HandleShowAttachmentsCommand);
101 } 102 }
102 103
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index ae0ad02..d764936 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -126,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
126 { 126 {
127 scene.RegisterModuleInterface<IGroupsModule>(this); 127 scene.RegisterModuleInterface<IGroupsModule>(this);
128 scene.AddCommand( 128 scene.AddCommand(
129 "debug", 129 "Debug",
130 this, 130 this,
131 "debug groups verbose", 131 "debug groups verbose",
132 "debug groups verbose <true|false>", 132 "debug groups verbose <true|false>",
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..32549d6 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/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index c7e3a7a..57d9217 100644
--- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
+++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
49 /// (such as land transfers). There is no money code here! Use FORGE as an example for money code. 49 /// (such as land transfers). There is no money code here! Use FORGE as an example for money code.
50 /// Demo Economy/Money Module. This is a purposely crippled module! 50 /// Demo Economy/Money Module. This is a purposely crippled module!
51 /// // To land transfer you need to add: 51 /// // To land transfer you need to add:
52 /// -helperuri <ADDRESS TO THIS SERVER> 52 /// -helperuri http://serveraddress:port/
53 /// to the command line parameters you use to start up your client 53 /// to the command line parameters you use to start up your client
54 /// This commonly looks like -helperuri http://127.0.0.1:9000/ 54 /// This commonly looks like -helperuri http://127.0.0.1:9000/
55 /// 55 ///
@@ -116,10 +116,9 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
116 } 116 }
117 117
118 /// <summary> 118 /// <summary>
119 /// Startup 119 /// Called on startup so the module can be configured.
120 /// </summary> 120 /// </summary>
121 /// <param name="scene"></param> 121 /// <param name="config">Configuration source.</param>
122 /// <param name="config"></param>
123 public void Initialise(IConfigSource config) 122 public void Initialise(IConfigSource config)
124 { 123 {
125 m_gConfig = config; 124 m_gConfig = config;
@@ -674,9 +673,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
674 } 673 }
675 674
676 /// <summary> 675 /// <summary>
677 /// When the client closes the connection we remove their accounting info from memory to free up resources. 676 /// When the client closes the connection we remove their accounting
677 /// info from memory to free up resources.
678 /// </summary> 678 /// </summary>
679 /// <param name="AgentID"></param> 679 /// <param name="AgentID">UUID of agent</param>
680 /// <param name="scene">Scene the agent was connected to.</param>
681 /// <see cref="OpenSim.Region.Framework.Scenes.EventManager.ClientClosed"/>
680 public void ClientClosed(UUID AgentID, Scene scene) 682 public void ClientClosed(UUID AgentID, Scene scene)
681 { 683 {
682 684
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index ef4005b..365fd78 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/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
new file mode 100644
index 0000000..8b8758e
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
@@ -0,0 +1,227 @@
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 System.Text;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Console;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.OptionalModules.Avatar.Attachments
44{
45 /// <summary>
46 /// A module that just holds commands for inspecting avatar appearance.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")]
49 public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private Scene m_scene;
54
55 public string Name { get { return "Scene Commands Module"; } }
56
57 public Type ReplaceableInterface { get { return null; } }
58
59 public void Initialise(IConfigSource source)
60 {
61// m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE");
62 }
63
64 public void PostInitialise()
65 {
66// m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE");
67 }
68
69 public void Close()
70 {
71// m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE");
72 }
73
74 public void AddRegion(Scene scene)
75 {
76// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
77
78 m_scene = scene;
79
80 m_scene.RegisterModuleInterface<ISceneCommandsModule>(this);
81 }
82
83 public void RemoveRegion(Scene scene)
84 {
85// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
86 }
87
88 public void RegionLoaded(Scene scene)
89 {
90// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
91
92 scene.AddCommand(
93 "Debug", this, "debug scene get",
94 "debug scene get",
95 "List current scene options.",
96 "If active is false then main scene update and maintenance loops are suspended.\n"
97 + "If collisions is false then collisions with other objects are turned off.\n"
98 + "If pbackup is false then periodic scene backup is turned off.\n"
99 + "If physics is false then all physics objects are non-physical.\n"
100 + "If scripting is false then no scripting operations happen.\n"
101 + "If teleport is true then some extra teleport debug information is logged.\n"
102 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
103 HandleDebugSceneGetCommand);
104
105 scene.AddCommand(
106 "Debug", this, "debug scene set",
107 "debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false",
108 "Turn on scene debugging options.",
109 "If active is false then main scene update and maintenance loops are suspended.\n"
110 + "If collisions is false then collisions with other objects are turned off.\n"
111 + "If pbackup is false then periodic scene backup is turned off.\n"
112 + "If physics is false then all physics objects are non-physical.\n"
113 + "If scripting is false then no scripting operations happen.\n"
114 + "If teleport is true then some extra teleport debug information is logged.\n"
115 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
116 HandleDebugSceneSetCommand);
117 }
118
119 private void HandleDebugSceneGetCommand(string module, string[] args)
120 {
121 if (args.Length == 3)
122 {
123 if (MainConsole.Instance.ConsoleScene == null)
124 MainConsole.Instance.Output("Please use 'change region <regioname>' first");
125 else
126 OutputSceneDebugOptions();
127 }
128 else
129 {
130 MainConsole.Instance.Output("Usage: debug scene get");
131 }
132 }
133
134 private void OutputSceneDebugOptions()
135 {
136 ConsoleDisplayList cdl = new ConsoleDisplayList();
137 cdl.AddRow("active", m_scene.Active);
138 cdl.AddRow("pbackup", m_scene.PeriodicBackup);
139 cdl.AddRow("physics", m_scene.PhysicsEnabled);
140 cdl.AddRow("scripting", m_scene.ScriptsEnabled);
141 cdl.AddRow("teleport", m_scene.DebugTeleporting);
142 cdl.AddRow("updates", m_scene.DebugUpdates);
143
144 MainConsole.Instance.Output(cdl.ToString());
145 }
146
147 private void HandleDebugSceneSetCommand(string module, string[] args)
148 {
149 if (args.Length == 5)
150 {
151 if (MainConsole.Instance.ConsoleScene == null)
152 {
153 MainConsole.Instance.Output("Please use 'change region <regioname>' first");
154 }
155 else
156 {
157 string key = args[3];
158 string value = args[4];
159 SetSceneDebugOptions(new Dictionary<string, string>() { { key, value } });
160
161 MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
162 }
163 }
164 else
165 {
166 MainConsole.Instance.Output(
167 "Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false");
168 }
169 }
170
171 public void SetSceneDebugOptions(Dictionary<string, string> options)
172 {
173 if (options.ContainsKey("active"))
174 {
175 bool active;
176
177 if (bool.TryParse(options["active"], out active))
178 m_scene.Active = active;
179 }
180
181 if (options.ContainsKey("pbackup"))
182 {
183 bool active;
184
185 if (bool.TryParse(options["pbackup"], out active))
186 m_scene.PeriodicBackup = active;
187 }
188
189 if (options.ContainsKey("scripting"))
190 {
191 bool enableScripts = true;
192 if (bool.TryParse(options["scripting"], out enableScripts))
193 m_scene.ScriptsEnabled = enableScripts;
194 }
195
196 if (options.ContainsKey("physics"))
197 {
198 bool enablePhysics;
199 if (bool.TryParse(options["physics"], out enablePhysics))
200 m_scene.PhysicsEnabled = enablePhysics;
201 }
202
203// if (options.ContainsKey("collisions"))
204// {
205// // TODO: Implement. If false, should stop objects colliding, though possibly should still allow
206// // the avatar themselves to collide with the ground.
207// }
208
209 if (options.ContainsKey("teleport"))
210 {
211 bool enableTeleportDebugging;
212 if (bool.TryParse(options["teleport"], out enableTeleportDebugging))
213 m_scene.DebugTeleporting = enableTeleportDebugging;
214 }
215
216 if (options.ContainsKey("updates"))
217 {
218 bool enableUpdateDebugging;
219 if (bool.TryParse(options["updates"], out enableUpdateDebugging))
220 {
221 m_scene.DebugUpdates = enableUpdateDebugging;
222 GcNotify.Enabled = enableUpdateDebugging;
223 }
224 }
225 }
226 }
227} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
index 7ab2a03..373c7e0 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
49 49
50 public PhysicsScene GetScene(string sceneIdentifier) 50 public PhysicsScene GetScene(string sceneIdentifier)
51 { 51 {
52 return new BasicScene(sceneIdentifier); 52 return new BasicScene(GetName(), sceneIdentifier);
53 } 53 }
54 54
55 public string GetName() 55 public string GetName()
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
index f5826ed..c4b9117 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
@@ -49,8 +49,10 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
49 49
50 //protected internal string sceneIdentifier; 50 //protected internal string sceneIdentifier;
51 51
52 public BasicScene(string _sceneIdentifier) 52 public BasicScene(string engineType, string _sceneIdentifier)
53 { 53 {
54 EngineType = engineType;
55 Name = EngineType + "/" + _sceneIdentifier;
54 //sceneIdentifier = _sceneIdentifier; 56 //sceneIdentifier = _sceneIdentifier;
55 } 57 }
56 58
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
new file mode 100644
index 0000000..d91c47f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
@@ -0,0 +1,814 @@
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.Reflection;
30using log4net;
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37public sealed class BSCharacter : BSPhysObject
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 // private bool _stopped;
43 private OMV.Vector3 _size;
44 private bool _grabbed;
45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore;
54 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType;
57 private bool _isPhysical;
58 private bool _flying;
59 private bool _setAlwaysRun;
60 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic;
66 private float _buoyancy;
67
68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71
72 private BSVMotor _velocityMotor;
73
74 private OMV.Vector3 _PIDTarget;
75 private bool _usePID;
76 private float _PIDTau;
77 private bool _useHoverPID;
78 private float _PIDHoverHeight;
79 private PIDHoverType _PIDHoverType;
80 private float _PIDHoverTao;
81
82 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
83 : base(parent_scene, localID, avName, "BSCharacter")
84 {
85 _physicsActorType = (int)ActorTypes.Agent;
86 _position = pos;
87
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values.
90 _size = size;
91 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
92 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
93
94 // A motor to control the acceleration and deceleration of the avatar movement.
95 // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
96 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
97 // Infinite decay and timescale values so motor only changes current to target values.
98 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
99 0.2f, // time scale
100 BSMotor.Infinite, // decay time scale
101 BSMotor.InfiniteVector, // friction timescale
102 1f // efficiency
103 );
104 _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
105
106 _flying = isFlying;
107 _orientation = OMV.Quaternion.Identity;
108 _velocity = OMV.Vector3.Zero;
109 _appliedVelocity = OMV.Vector3.Zero;
110 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
111 _currentFriction = BSParam.AvatarStandingFriction;
112 _avatarDensity = BSParam.AvatarDensity;
113
114 // The dimensions of the avatar capsule are kept in the scale.
115 // Physics creates a unit capsule which is scaled by the physics engine.
116 ComputeAvatarScale(_size);
117 // set _avatarVolume and _mass based on capsule size, _density and Scale
118 ComputeAvatarVolumeAndMass();
119 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
120 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
121
122 // do actual creation in taint time
123 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
124 {
125 DetailLog("{0},BSCharacter.create,taint", LocalID);
126 // New body and shape into PhysBody and PhysShape
127 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
128
129 SetPhysicalProperties();
130 });
131 return;
132 }
133
134 // called when this character is being destroyed and the resources should be released
135 public override void Destroy()
136 {
137 base.Destroy();
138
139 DetailLog("{0},BSCharacter.Destroy", LocalID);
140 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
141 {
142 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
143 PhysBody.Clear();
144 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
145 PhysShape.Clear();
146 });
147 }
148
149 private void SetPhysicalProperties()
150 {
151 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
152
153 ZeroMotion(true);
154 ForcePosition = _position;
155 // Set the velocity and compute the proper friction
156 ForceVelocity = _velocity;
157 // Setting the current and target in the motor will cause it to start computing any deceleration.
158 _velocityMotor.Reset();
159 _velocityMotor.SetCurrent(_velocity);
160 _velocityMotor.SetTarget(_velocity);
161 _velocityMotor.Enabled = false;
162
163 // This will enable or disable the flying buoyancy of the avatar.
164 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
165 Flying = _flying;
166
167 BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution);
168 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
169 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
170 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
171 if (BSParam.CcdMotionThreshold > 0f)
172 {
173 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
174 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
175 }
176
177 UpdatePhysicalMassProperties(RawMass, false);
178
179 // Make so capsule does not fall over
180 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
181
182 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
183
184 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
185
186 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
187 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
188 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
189
190 // Do this after the object has been added to the world
191 PhysBody.collisionType = CollisionType.Avatar;
192 PhysBody.ApplyCollisionMask();
193 }
194
195 public override void RequestPhysicsterseUpdate()
196 {
197 base.RequestPhysicsterseUpdate();
198 }
199 // No one calls this method so I don't know what it could possibly mean
200 public override bool Stopped { get { return false; } }
201
202 public override OMV.Vector3 Size {
203 get
204 {
205 // Avatar capsule size is kept in the scale parameter.
206 return _size;
207 }
208
209 set {
210 // When an avatar's size is set, only the height is changed.
211 _size = value;
212 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
213 // replace with the default values.
214 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
215 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
216
217 ComputeAvatarScale(_size);
218 ComputeAvatarVolumeAndMass();
219 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
220 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
221
222 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
223 {
224 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
225 {
226 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
227 UpdatePhysicalMassProperties(RawMass, true);
228 // Make sure this change appears as a property update event
229 BulletSimAPI.PushUpdate2(PhysBody.ptr);
230 }
231 });
232
233 }
234 }
235
236 public override PrimitiveBaseShape Shape
237 {
238 set { BaseShape = value; }
239 }
240 // I want the physics engine to make an avatar capsule
241 public override BSPhysicsShapeType PreferredPhysicalShape
242 {
243 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
244 }
245
246 public override bool Grabbed {
247 set { _grabbed = value; }
248 }
249 public override bool Selected {
250 set { _selected = value; }
251 }
252 public override void CrossingFailure() { return; }
253 public override void link(PhysicsActor obj) { return; }
254 public override void delink() { return; }
255
256 // Set motion values to zero.
257 // Do it to the properties so the values get set in the physics engine.
258 // Push the setting of the values to the viewer.
259 // Called at taint time!
260 public override void ZeroMotion(bool inTaintTime)
261 {
262 _velocity = OMV.Vector3.Zero;
263 _acceleration = OMV.Vector3.Zero;
264 _rotationalVelocity = OMV.Vector3.Zero;
265
266 // Zero some other properties directly into the physics engine
267 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
268 {
269 if (PhysBody.HasPhysicalBody)
270 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
271 });
272 }
273 public override void ZeroAngularMotion(bool inTaintTime)
274 {
275 _rotationalVelocity = OMV.Vector3.Zero;
276
277 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
278 {
279 if (PhysBody.HasPhysicalBody)
280 {
281 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
282 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
283 // The next also get rid of applied linear force but the linear velocity is untouched.
284 BulletSimAPI.ClearForces2(PhysBody.ptr);
285 }
286 });
287 }
288
289
290 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
291
292 public override OMV.Vector3 RawPosition
293 {
294 get { return _position; }
295 set { _position = value; }
296 }
297 public override OMV.Vector3 Position {
298 get {
299 // Don't refetch the position because this function is called a zillion times
300 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
301 return _position;
302 }
303 set {
304 _position = value;
305 PositionSanityCheck();
306
307 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
308 {
309 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
310 if (PhysBody.HasPhysicalBody)
311 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
312 });
313 }
314 }
315 public override OMV.Vector3 ForcePosition {
316 get {
317 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
318 return _position;
319 }
320 set {
321 _position = value;
322 PositionSanityCheck();
323 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
324 }
325 }
326
327
328 // Check that the current position is sane and, if not, modify the position to make it so.
329 // Check for being below terrain or on water.
330 // Returns 'true' of the position was made sane by some action.
331 private bool PositionSanityCheck()
332 {
333 bool ret = false;
334
335 // TODO: check for out of bounds
336 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
337 {
338 // The character 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
344 // If below the ground, move the avatar up
345 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
346 if (Position.Z < terrainHeight)
347 {
348 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
349 _position.Z = terrainHeight + 2.0f;
350 ret = true;
351 }
352 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
353 {
354 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
355 if (Position.Z < waterHeight)
356 {
357 _position.Z = waterHeight;
358 ret = true;
359 }
360 }
361
362 return ret;
363 }
364
365 // A version of the sanity check that also makes sure a new position value is
366 // pushed back to the physics engine. This routine would be used by anyone
367 // who is not already pushing the value.
368 private bool PositionSanityCheck(bool inTaintTime)
369 {
370 bool ret = false;
371 if (PositionSanityCheck())
372 {
373 // The new position value must be pushed into the physics engine but we can't
374 // just assign to "Position" because of potential call loops.
375 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
376 {
377 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
378 if (PhysBody.HasPhysicalBody)
379 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
380 });
381 ret = true;
382 }
383 return ret;
384 }
385
386 public override float Mass { get { return _mass; } }
387
388 // used when we only want this prim's mass and not the linkset thing
389 public override float RawMass {
390 get {return _mass; }
391 }
392 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
393 {
394 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
395 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
396 }
397
398 public override OMV.Vector3 Force {
399 get { return _force; }
400 set {
401 _force = value;
402 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
403 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
404 {
405 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
406 if (PhysBody.HasPhysicalBody)
407 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
408 });
409 }
410 }
411
412 public bool TouchingGround()
413 {
414 bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr);
415 return ret;
416 }
417 // Avatars don't do vehicles
418 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
419 public override void VehicleFloatParam(int param, float value) { }
420 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
421 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
422 public override void VehicleFlags(int param, bool remove) { }
423
424 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
425 public override void SetVolumeDetect(int param) { return; }
426
427 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
428 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
429
430 // Sets the target in the motor. This starts the changing of the avatar's velocity.
431 public override OMV.Vector3 TargetVelocity
432 {
433 get
434 {
435 return _velocityMotor.TargetValue;
436 }
437 set
438 {
439 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
440
441 if (!_flying)
442 if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f)
443 if (!TouchingGround())
444 value.Z = _velocity.Z;
445 if (_setAlwaysRun)
446 value *= 1.3f;
447
448 OMV.Vector3 targetVel = value;
449
450 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
451 {
452
453 _velocityMotor.Reset();
454 _velocityMotor.SetTarget(targetVel);
455 _velocityMotor.SetCurrent(_velocity);
456 _velocityMotor.Enabled = true;
457
458 // Make sure a property update happens next step so the motor gets incorporated.
459 BulletSimAPI.PushUpdate2(PhysBody.ptr);
460 });
461 }
462 }
463 // Directly setting velocity means this is what the user really wants now.
464 public override OMV.Vector3 Velocity {
465 get { return _velocity; }
466 set {
467 _velocity = value;
468 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
469 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
470 {
471 _velocityMotor.Reset();
472 _velocityMotor.SetCurrent(_velocity);
473 _velocityMotor.SetTarget(_velocity);
474 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
475 _velocityMotor.Enabled = false;
476
477 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
478 ForceVelocity = _velocity;
479 });
480 }
481 }
482 public override OMV.Vector3 ForceVelocity {
483 get { return _velocity; }
484 set {
485 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
486
487 _velocity = value;
488 // Depending on whether the avatar is moving or not, change the friction
489 // to keep the avatar from slipping around
490 if (_velocity.Length() == 0)
491 {
492 if (_currentFriction != BSParam.AvatarStandingFriction)
493 {
494 _currentFriction = BSParam.AvatarStandingFriction;
495 if (PhysBody.HasPhysicalBody)
496 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
497 }
498 }
499 else
500 {
501 if (_currentFriction != BSParam.AvatarFriction)
502 {
503 _currentFriction = BSParam.AvatarFriction;
504 if (PhysBody.HasPhysicalBody)
505 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
506 }
507 }
508 // Remember the set velocity so we can suppress the reduction by friction, ...
509 _appliedVelocity = value;
510
511 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
512 BulletSimAPI.Activate2(PhysBody.ptr, true);
513 }
514 }
515 public override OMV.Vector3 Torque {
516 get { return _torque; }
517 set { _torque = value;
518 }
519 }
520 public override float CollisionScore {
521 get { return _collisionScore; }
522 set { _collisionScore = value;
523 }
524 }
525 public override OMV.Vector3 Acceleration {
526 get { return _acceleration; }
527 set { _acceleration = value; }
528 }
529 public override OMV.Quaternion RawOrientation
530 {
531 get { return _orientation; }
532 set { _orientation = value; }
533 }
534 public override OMV.Quaternion Orientation {
535 get { return _orientation; }
536 set {
537 _orientation = value;
538 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
539 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
540 {
541 if (PhysBody.HasPhysicalBody)
542 {
543 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
544 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
545 }
546 });
547 }
548 }
549 // Go directly to Bullet to get/set the value.
550 public override OMV.Quaternion ForceOrientation
551 {
552 get
553 {
554 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
555 return _orientation;
556 }
557 set
558 {
559 _orientation = value;
560 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
561 }
562 }
563 public override int PhysicsActorType {
564 get { return _physicsActorType; }
565 set { _physicsActorType = value;
566 }
567 }
568 public override bool IsPhysical {
569 get { return _isPhysical; }
570 set { _isPhysical = value;
571 }
572 }
573 public override bool IsSolid {
574 get { return true; }
575 }
576 public override bool IsStatic {
577 get { return false; }
578 }
579 public override bool Flying {
580 get { return _flying; }
581 set {
582 _flying = value;
583
584 // simulate flying by changing the effect of gravity
585 Buoyancy = ComputeBuoyancyFromFlying(_flying);
586 }
587 }
588 // Flying is implimented by changing the avatar's buoyancy.
589 // Would this be done better with a vehicle type?
590 private float ComputeBuoyancyFromFlying(bool ifFlying) {
591 return ifFlying ? 1f : 0f;
592 }
593 public override bool
594 SetAlwaysRun {
595 get { return _setAlwaysRun; }
596 set { _setAlwaysRun = value; }
597 }
598 public override bool ThrottleUpdates {
599 get { return _throttleUpdates; }
600 set { _throttleUpdates = value; }
601 }
602 public override bool IsColliding {
603 get { return (CollidingStep == PhysicsScene.SimulationStep); }
604 set { _isColliding = value; }
605 }
606 public override bool CollidingGround {
607 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
608 set { CollidingGround = value; }
609 }
610 public override bool CollidingObj {
611 get { return _collidingObj; }
612 set { _collidingObj = value; }
613 }
614 public override bool FloatOnWater {
615 set {
616 _floatOnWater = value;
617 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
618 {
619 if (PhysBody.HasPhysicalBody)
620 {
621 if (_floatOnWater)
622 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
623 else
624 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
625 }
626 });
627 }
628 }
629 public override OMV.Vector3 RotationalVelocity {
630 get { return _rotationalVelocity; }
631 set { _rotationalVelocity = value; }
632 }
633 public override OMV.Vector3 ForceRotationalVelocity {
634 get { return _rotationalVelocity; }
635 set { _rotationalVelocity = value; }
636 }
637 public override bool Kinematic {
638 get { return _kinematic; }
639 set { _kinematic = value; }
640 }
641 // neg=fall quickly, 0=1g, 1=0g, pos=float up
642 public override float Buoyancy {
643 get { return _buoyancy; }
644 set { _buoyancy = value;
645 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
646 {
647 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
648 ForceBuoyancy = _buoyancy;
649 });
650 }
651 }
652 public override float ForceBuoyancy {
653 get { return _buoyancy; }
654 set {
655 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
656
657 _buoyancy = value;
658 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
659 // Buoyancy is faked by changing the gravity applied to the object
660 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
661 if (PhysBody.HasPhysicalBody)
662 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
663 }
664 }
665
666 // Used for MoveTo
667 public override OMV.Vector3 PIDTarget {
668 set { _PIDTarget = value; }
669 }
670 public override bool PIDActive {
671 set { _usePID = value; }
672 }
673 public override float PIDTau {
674 set { _PIDTau = value; }
675 }
676
677 // Used for llSetHoverHeight and maybe vehicle height
678 // Hover Height will override MoveTo target's Z
679 public override bool PIDHoverActive {
680 set { _useHoverPID = value; }
681 }
682 public override float PIDHoverHeight {
683 set { _PIDHoverHeight = value; }
684 }
685 public override PIDHoverType PIDHoverType {
686 set { _PIDHoverType = value; }
687 }
688 public override float PIDHoverTau {
689 set { _PIDHoverTao = value; }
690 }
691
692 // For RotLookAt
693 public override OMV.Quaternion APIDTarget { set { return; } }
694 public override bool APIDActive { set { return; } }
695 public override float APIDStrength { set { return; } }
696 public override float APIDDamping { set { return; } }
697
698 public override void AddForce(OMV.Vector3 force, bool pushforce) {
699 if (force.IsFinite())
700 {
701 _force.X += force.X;
702 _force.Y += force.Y;
703 _force.Z += force.Z;
704 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
705 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
706 {
707 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
708 if (PhysBody.HasPhysicalBody)
709 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
710 });
711 }
712 else
713 {
714 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader);
715 }
716 //m_lastUpdateSent = false;
717 }
718
719 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
720 }
721 public override void SetMomentum(OMV.Vector3 momentum) {
722 }
723
724 private void ComputeAvatarScale(OMV.Vector3 size)
725 {
726 OMV.Vector3 newScale = size;
727 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
728 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
729
730 // From the total height, remove the capsule half spheres that are at each end
731 // The 1.15f came from ODE. Not sure what this factors in.
732 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
733
734 // The total scale height is the central cylindar plus the caps on the two ends.
735 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
736
737 // Convert diameters to radii and height to half height -- the way Bullet expects it.
738 Scale = newScale / 2f;
739 }
740
741 // set _avatarVolume and _mass based on capsule size, _density and Scale
742 private void ComputeAvatarVolumeAndMass()
743 {
744 _avatarVolume = (float)(
745 Math.PI
746 * Scale.X
747 * Scale.Y // the area of capsule cylinder
748 * Scale.Z // times height of capsule cylinder
749 + 1.33333333f
750 * Math.PI
751 * Scale.X
752 * Math.Min(Scale.X, Scale.Y)
753 * Scale.Y // plus the volume of the capsule end caps
754 );
755 _mass = _avatarDensity * _avatarVolume;
756 }
757
758 // The physics engine says that properties have updated. Update same and inform
759 // the world that things have changed.
760 public override void UpdateProperties(EntityProperties entprop)
761 {
762 _position = entprop.Position;
763 _orientation = entprop.Rotation;
764 _velocity = entprop.Velocity;
765 _acceleration = entprop.Acceleration;
766 _rotationalVelocity = entprop.RotationalVelocity;
767
768 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
769 PositionSanityCheck(true);
770
771 if (_velocityMotor.Enabled)
772 {
773 // TODO: Decide if the step parameters should be changed depending on the avatar's
774 // state (flying, colliding, ...).
775
776 OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep);
777
778 // If falling, we keep the world's downward vector no matter what the other axis specify.
779 if (!Flying && !IsColliding)
780 {
781 stepVelocity.Z = entprop.Velocity.Z;
782 DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
783 }
784
785 // If the user has said stop and we've stopped applying velocity correction,
786 // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer.
787 if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero)
788 {
789 ZeroMotion(true);
790 stepVelocity = OMV.Vector3.Zero;
791 _velocityMotor.Enabled = false;
792 DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor);
793 }
794
795 _velocity = stepVelocity;
796 entprop.Velocity = _velocity;
797 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
798 }
799
800 // remember the current and last set values
801 LastEntityProperties = CurrentEntityProperties;
802 CurrentEntityProperties = entprop;
803
804 // Tell the linkset about value changes
805 Linkset.UpdateProperties(this, true);
806
807 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
808 // base.RequestPhysicsterseUpdate();
809
810 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
811 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
812 }
813}
814}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs
new file mode 100644
index 0000000..f1bed39
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs
@@ -0,0 +1,135 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public abstract class BSConstraint : IDisposable
36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
39 protected BulletWorld m_world;
40 protected BulletBody m_body1;
41 protected BulletBody m_body2;
42 protected BulletConstraint m_constraint;
43 protected bool m_enabled = false;
44
45 public BulletBody Body1 { get { return m_body1; } }
46 public BulletBody Body2 { get { return m_body2; } }
47 public BulletConstraint Constraint { get { return m_constraint; } }
48 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } }
50
51 public BSConstraint()
52 {
53 }
54
55 public virtual void Dispose()
56 {
57 if (m_enabled)
58 {
59 m_enabled = false;
60 if (m_constraint.HasPhysicalConstraint)
61 {
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}",
64 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString(),
66 m_body2.ID, m_body2.ptr.ToString(),
67 success);
68 m_constraint.Clear();
69 }
70 }
71 }
72
73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
74 {
75 bool ret = false;
76 if (m_enabled)
77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
78 return ret;
79 }
80
81 public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
82 {
83 bool ret = false;
84 if (m_enabled)
85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
86 return ret;
87 }
88
89 public virtual bool SetSolverIterations(float cnt)
90 {
91 bool ret = false;
92 if (m_enabled)
93 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
95 ret = true;
96 }
97 return ret;
98 }
99
100 public virtual bool CalculateTransforms()
101 {
102 bool ret = false;
103 if (m_enabled)
104 {
105 // Recompute the internal transforms
106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
107 ret = true;
108 }
109 return ret;
110 }
111
112 // Reset this constraint making sure it has all its internal structures
113 // recomputed and is enabled and ready to go.
114 public virtual bool RecomputeConstraintVariables(float mass)
115 {
116 bool ret = false;
117 if (m_enabled)
118 {
119 ret = CalculateTransforms();
120 if (ret)
121 {
122 // Setting an object's mass to zero (making it static like when it's selected)
123 // automatically disables the constraints.
124 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true));
126 }
127 else
128 {
129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
130 }
131 }
132 return ret;
133 }
134}
135}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs
new file mode 100644
index 0000000..d1e3f55
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs
@@ -0,0 +1,153 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public sealed class BSConstraint6Dof : BSConstraint
36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
41 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
46 {
47 m_world = world;
48 m_body1 = obj1;
49 m_body2 = obj2;
50 m_constraint = new BulletConstraint(
51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
52 frame1, frame1rot,
53 frame2, frame2rot,
54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
59 }
60
61 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 {
65 m_world = world;
66 m_body1 = obj1;
67 m_body2 = obj2;
68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
75 m_enabled = false;
76 }
77 else
78 {
79 m_constraint = new BulletConstraint(
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
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(),
85 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
86 if (!m_constraint.HasPhysicalConstraint)
87 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID);
90 m_enabled = false;
91 }
92 else
93 {
94 m_enabled = true;
95 }
96 }
97 }
98
99 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
100 {
101 bool ret = false;
102 if (m_enabled)
103 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
105 ret = true;
106 }
107 return ret;
108 }
109
110 public bool SetCFMAndERP(float cfm, float erp)
111 {
112 bool ret = false;
113 if (m_enabled)
114 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true;
119 }
120 return ret;
121 }
122
123 public bool UseFrameOffset(bool useOffset)
124 {
125 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
129 return ret;
130 }
131
132 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
133 {
134 bool ret = false;
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled)
137 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 }
142 return ret;
143 }
144
145 public bool SetBreakingImpulseThreshold(float threshold)
146 {
147 bool ret = false;
148 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
150 return ret;
151 }
152}
153}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs
new file mode 100644
index 0000000..87d1e44
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs
@@ -0,0 +1,180 @@
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 log4net;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35
36public sealed class BSConstraintCollection : IDisposable
37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
40
41 delegate bool ConstraintAction(BSConstraint constrain);
42
43 private List<BSConstraint> m_constraints;
44 private BulletWorld m_world;
45
46 public BSConstraintCollection(BulletWorld world)
47 {
48 m_world = world;
49 m_constraints = new List<BSConstraint>();
50 }
51
52 public void Dispose()
53 {
54 this.Clear();
55 }
56
57 public void Clear()
58 {
59 lock (m_constraints)
60 {
61 foreach (BSConstraint cons in m_constraints)
62 {
63 cons.Dispose();
64 }
65 m_constraints.Clear();
66 }
67 }
68
69 public bool AddConstraint(BSConstraint cons)
70 {
71 lock (m_constraints)
72 {
73 // There is only one constraint between any bodies. Remove any old just to make sure.
74 RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
75
76 m_constraints.Add(cons);
77 }
78
79 return true;
80 }
81
82 // Get the constraint between two bodies. There can be only one.
83 // Return 'true' if a constraint was found.
84 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
85 {
86 bool found = false;
87 BSConstraint foundConstraint = null;
88
89 uint lookingID1 = body1.ID;
90 uint lookingID2 = body2.ID;
91 lock (m_constraints)
92 {
93 foreach (BSConstraint constrain in m_constraints)
94 {
95 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
96 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
97 {
98 foundConstraint = constrain;
99 found = true;
100 break;
101 }
102 }
103 }
104 returnConstraint = foundConstraint;
105 return found;
106 }
107
108 // Remove any constraint between the passed bodies.
109 // Presumed there is only one such constraint possible.
110 // Return 'true' if a constraint was found and destroyed.
111 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
112 {
113 bool ret = false;
114 lock (m_constraints)
115 {
116 BSConstraint constrain;
117 if (this.TryGetConstraint(body1, body2, out constrain))
118 {
119 // remove the constraint from our collection
120 RemoveAndDestroyConstraint(constrain);
121 ret = true;
122 }
123 }
124
125 return ret;
126 }
127
128 // The constraint MUST exist in the collection
129 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
130 {
131 lock (m_constraints)
132 {
133 // remove the constraint from our collection
134 m_constraints.Remove(constrain);
135 }
136 // tell the engine that all its structures need to be freed
137 constrain.Dispose();
138 // we destroyed something
139 return true;
140 }
141
142 // Remove all constraints that reference the passed body.
143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 {
146 List<BSConstraint> toRemove = new List<BSConstraint>();
147 uint lookingID = body1.ID;
148 lock (m_constraints)
149 {
150 foreach (BSConstraint constrain in m_constraints)
151 {
152 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
153 {
154 toRemove.Add(constrain);
155 }
156 }
157 foreach (BSConstraint constrain in toRemove)
158 {
159 m_constraints.Remove(constrain);
160 constrain.Dispose();
161 }
162 }
163 return (toRemove.Count > 0);
164 }
165
166 public bool RecalculateAllConstraints()
167 {
168 bool ret = false;
169 lock (m_constraints)
170 {
171 foreach (BSConstraint constrain in m_constraints)
172 {
173 constrain.CalculateTransforms();
174 ret = true;
175 }
176 }
177 return ret;
178 }
179}
180}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs
new file mode 100644
index 0000000..fbd1bc0
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs
@@ -0,0 +1,57 @@
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 OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public sealed class BSConstraintHinge : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38
39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 {
44 m_world = world;
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = new BulletConstraint(
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 pivotInA, pivotInB,
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true;
53 }
54
55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
new file mode 100644
index 0000000..415ad4f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
@@ -0,0 +1,1377 @@
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 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * of Creative Commons Attribution-Share Alike 3.0
30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31 */
32
33using System;
34using System.Collections.Generic;
35using System.Reflection;
36using System.Runtime.InteropServices;
37using OpenMetaverse;
38using OpenSim.Region.Physics.Manager;
39
40namespace OpenSim.Region.Physics.BulletSNPlugin
41{
42 public sealed class BSDynamics
43 {
44 private static string LogHeader = "[BULLETSIM VEHICLE]";
45
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; }
49
50 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass;
52
53 // Vehicle properties
54 public Vehicle Type { get; set; }
55
56 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
57 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
58 // HOVER_TERRAIN_ONLY
59 // HOVER_GLOBAL_HEIGHT
60 // NO_DEFLECTION_UP
61 // HOVER_WATER_ONLY
62 // HOVER_UP_ONLY
63 // LIMIT_MOTOR_UP
64 // LIMIT_ROLL_ONLY
65 private Vector3 m_BlockingEndPoint = Vector3.Zero;
66 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
67 private Quaternion m_referenceFrame = Quaternion.Identity;
68
69 // Linear properties
70 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
71 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
74 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
75 private float m_linearMotorDecayTimescale = 0;
76 private float m_linearMotorTimescale = 0;
77 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
78 private Vector3 m_lastPositionVector = Vector3.Zero;
79 // private bool m_LinearMotorSetLastFrame = false;
80 // private Vector3 m_linearMotorOffset = Vector3.Zero;
81
82 //Angular properties
83 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
85 // private int m_angularMotorApply = 0; // application frame counter
86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
90 private Vector3 m_lastAngularVelocity = Vector3.Zero;
91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
92
93 //Deflection properties
94 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
95 private float m_angularDeflectionEfficiency = 0;
96 private float m_angularDeflectionTimescale = 0;
97 private float m_linearDeflectionEfficiency = 0;
98 private float m_linearDeflectionTimescale = 0;
99
100 //Banking properties
101 private float m_bankingEfficiency = 0;
102 private float m_bankingMix = 0;
103 private float m_bankingTimescale = 0;
104
105 //Hover and Buoyancy properties
106 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
107 private float m_VhoverHeight = 0f;
108 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
111 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
115
116 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
118 private float m_verticalAttractionEfficiency = 1.0f; // damped
119 private float m_verticalAttractionCutoff = 500f; // per the documentation
120 // Timescale > cutoff means no vert attractor.
121 private float m_verticalAttractionTimescale = 510f;
122
123 // Just some recomputed constants:
124 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
126
127 public BSDynamics(BSScene myScene, BSPrim myPrim)
128 {
129 PhysicsScene = myScene;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE;
132 }
133
134 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive
136 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; }
138 }
139
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
143 switch (pParam)
144 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
146 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
147 break;
148 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
150 break;
151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
154 break;
155 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
156 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
157 m_angularMotor.TimeScale = m_angularMotorTimescale;
158 break;
159 case Vehicle.BANKING_EFFICIENCY:
160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
161 break;
162 case Vehicle.BANKING_MIX:
163 m_bankingMix = Math.Max(pValue, 0.01f);
164 break;
165 case Vehicle.BANKING_TIMESCALE:
166 m_bankingTimescale = Math.Max(pValue, 0.01f);
167 break;
168 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
170 break;
171 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
173 break;
174 case Vehicle.HOVER_HEIGHT:
175 m_VhoverHeight = pValue;
176 break;
177 case Vehicle.HOVER_TIMESCALE:
178 m_VhoverTimescale = Math.Max(pValue, 0.01f);
179 break;
180 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
181 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
182 break;
183 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
185 break;
186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
192 m_linearMotor.TimeScale = m_linearMotorTimescale;
193 break;
194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
195 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
197 break;
198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
201 break;
202
203 // These are vector properties but the engine lets you use a single float value to
204 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
208 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
211 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
216 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
220 m_linearMotor.SetTarget(m_linearMotorDirection);
221 break;
222 case Vehicle.LINEAR_MOTOR_OFFSET:
223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
224 break;
225
226 }
227 }//end ProcessFloatVehicleParam
228
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
232 switch (pParam)
233 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec
240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE:
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION:
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection);
254 break;
255 case Vehicle.LINEAR_MOTOR_OFFSET:
256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break;
258 case Vehicle.BLOCK_EXIT:
259 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break;
261 }
262 }//end ProcessVectorVehicleParam
263
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
267 switch (pParam)
268 {
269 case Vehicle.REFERENCE_FRAME:
270 m_referenceFrame = pValue;
271 break;
272 case Vehicle.ROLL_FRAME:
273 m_RollreferenceFrame = pValue;
274 break;
275 }
276 }//end ProcessRotationVehicleParam
277
278 internal void ProcessVehicleFlags(int pParam, bool remove)
279 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1)
283 m_flags = (VehicleFlag)0;
284 else
285 {
286 if (remove)
287 m_flags &= ~parm;
288 else
289 m_flags |= parm;
290 }
291 }
292
293 internal void ProcessTypeChange(Vehicle pType)
294 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
296 // Set Defaults For Type
297 Type = pType;
298 switch (pType)
299 {
300 case Vehicle.TYPE_NONE:
301 m_linearMotorDirection = Vector3.Zero;
302 m_linearMotorTimescale = 0;
303 m_linearMotorDecayTimescale = 0;
304 m_linearFrictionTimescale = new Vector3(0, 0, 0);
305
306 m_angularMotorDirection = Vector3.Zero;
307 m_angularMotorDecayTimescale = 0;
308 m_angularMotorTimescale = 0;
309 m_angularFrictionTimescale = new Vector3(0, 0, 0);
310
311 m_VhoverHeight = 0;
312 m_VhoverEfficiency = 0;
313 m_VhoverTimescale = 0;
314 m_VehicleBuoyancy = 0;
315
316 m_linearDeflectionEfficiency = 1;
317 m_linearDeflectionTimescale = 1;
318
319 m_angularDeflectionEfficiency = 0;
320 m_angularDeflectionTimescale = 1000;
321
322 m_verticalAttractionEfficiency = 0;
323 m_verticalAttractionTimescale = 0;
324
325 m_bankingEfficiency = 0;
326 m_bankingTimescale = 1000;
327 m_bankingMix = 1;
328
329 m_referenceFrame = Quaternion.Identity;
330 m_flags = (VehicleFlag)0;
331
332 break;
333
334 case Vehicle.TYPE_SLED:
335 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1000;
337 m_linearMotorDecayTimescale = 120;
338 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
339
340 m_angularMotorDirection = Vector3.Zero;
341 m_angularMotorTimescale = 1000;
342 m_angularMotorDecayTimescale = 120;
343 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
344
345 m_VhoverHeight = 0;
346 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
347 m_VhoverTimescale = 10;
348 m_VehicleBuoyancy = 0;
349
350 m_linearDeflectionEfficiency = 1;
351 m_linearDeflectionTimescale = 1;
352
353 m_angularDeflectionEfficiency = 1;
354 m_angularDeflectionTimescale = 1000;
355
356 m_verticalAttractionEfficiency = 0;
357 m_verticalAttractionTimescale = 0;
358
359 m_bankingEfficiency = 0;
360 m_bankingTimescale = 10;
361 m_bankingMix = 1;
362
363 m_referenceFrame = Quaternion.Identity;
364 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
365 | VehicleFlag.HOVER_TERRAIN_ONLY
366 | VehicleFlag.HOVER_GLOBAL_HEIGHT
367 | VehicleFlag.HOVER_UP_ONLY);
368 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
369 | VehicleFlag.LIMIT_ROLL_ONLY
370 | VehicleFlag.LIMIT_MOTOR_UP);
371
372 break;
373 case Vehicle.TYPE_CAR:
374 m_linearMotorDirection = Vector3.Zero;
375 m_linearMotorTimescale = 1;
376 m_linearMotorDecayTimescale = 60;
377 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
378
379 m_angularMotorDirection = Vector3.Zero;
380 m_angularMotorTimescale = 1;
381 m_angularMotorDecayTimescale = 0.8f;
382 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
383
384 m_VhoverHeight = 0;
385 m_VhoverEfficiency = 0;
386 m_VhoverTimescale = 1000;
387 m_VehicleBuoyancy = 0;
388
389 m_linearDeflectionEfficiency = 1;
390 m_linearDeflectionTimescale = 2;
391
392 m_angularDeflectionEfficiency = 0;
393 m_angularDeflectionTimescale = 10;
394
395 m_verticalAttractionEfficiency = 1f;
396 m_verticalAttractionTimescale = 10f;
397
398 m_bankingEfficiency = -0.2f;
399 m_bankingMix = 1;
400 m_bankingTimescale = 1;
401
402 m_referenceFrame = Quaternion.Identity;
403 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
404 | VehicleFlag.HOVER_TERRAIN_ONLY
405 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
406 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
407 | VehicleFlag.LIMIT_ROLL_ONLY
408 | VehicleFlag.LIMIT_MOTOR_UP
409 | VehicleFlag.HOVER_UP_ONLY);
410 break;
411 case Vehicle.TYPE_BOAT:
412 m_linearMotorDirection = Vector3.Zero;
413 m_linearMotorTimescale = 5;
414 m_linearMotorDecayTimescale = 60;
415 m_linearFrictionTimescale = new Vector3(10, 3, 2);
416
417 m_angularMotorDirection = Vector3.Zero;
418 m_angularMotorTimescale = 4;
419 m_angularMotorDecayTimescale = 4;
420 m_angularFrictionTimescale = new Vector3(10,10,10);
421
422 m_VhoverHeight = 0;
423 m_VhoverEfficiency = 0.5f;
424 m_VhoverTimescale = 2;
425 m_VehicleBuoyancy = 1;
426
427 m_linearDeflectionEfficiency = 0.5f;
428 m_linearDeflectionTimescale = 3;
429
430 m_angularDeflectionEfficiency = 0.5f;
431 m_angularDeflectionTimescale = 5;
432
433 m_verticalAttractionEfficiency = 0.5f;
434 m_verticalAttractionTimescale = 5f;
435
436 m_bankingEfficiency = -0.3f;
437 m_bankingMix = 0.8f;
438 m_bankingTimescale = 1;
439
440 m_referenceFrame = Quaternion.Identity;
441 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
442 | VehicleFlag.HOVER_GLOBAL_HEIGHT
443 | VehicleFlag.LIMIT_ROLL_ONLY
444 | VehicleFlag.HOVER_UP_ONLY);
445 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
446 | VehicleFlag.LIMIT_MOTOR_UP
447 | VehicleFlag.HOVER_WATER_ONLY);
448 break;
449 case Vehicle.TYPE_AIRPLANE:
450 m_linearMotorDirection = Vector3.Zero;
451 m_linearMotorTimescale = 2;
452 m_linearMotorDecayTimescale = 60;
453 m_linearFrictionTimescale = new Vector3(200, 10, 5);
454
455 m_angularMotorDirection = Vector3.Zero;
456 m_angularMotorTimescale = 4;
457 m_angularMotorDecayTimescale = 4;
458 m_angularFrictionTimescale = new Vector3(20, 20, 20);
459
460 m_VhoverHeight = 0;
461 m_VhoverEfficiency = 0.5f;
462 m_VhoverTimescale = 1000;
463 m_VehicleBuoyancy = 0;
464
465 m_linearDeflectionEfficiency = 0.5f;
466 m_linearDeflectionTimescale = 3;
467
468 m_angularDeflectionEfficiency = 1;
469 m_angularDeflectionTimescale = 2;
470
471 m_verticalAttractionEfficiency = 0.9f;
472 m_verticalAttractionTimescale = 2f;
473
474 m_bankingEfficiency = 1;
475 m_bankingMix = 0.7f;
476 m_bankingTimescale = 2;
477
478 m_referenceFrame = Quaternion.Identity;
479 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
480 | VehicleFlag.HOVER_TERRAIN_ONLY
481 | VehicleFlag.HOVER_GLOBAL_HEIGHT
482 | VehicleFlag.HOVER_UP_ONLY
483 | VehicleFlag.NO_DEFLECTION_UP
484 | VehicleFlag.LIMIT_MOTOR_UP);
485 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
486 break;
487 case Vehicle.TYPE_BALLOON:
488 m_linearMotorDirection = Vector3.Zero;
489 m_linearMotorTimescale = 5;
490 m_linearFrictionTimescale = new Vector3(5, 5, 5);
491 m_linearMotorDecayTimescale = 60;
492
493 m_angularMotorDirection = Vector3.Zero;
494 m_angularMotorTimescale = 6;
495 m_angularFrictionTimescale = new Vector3(10, 10, 10);
496 m_angularMotorDecayTimescale = 10;
497
498 m_VhoverHeight = 5;
499 m_VhoverEfficiency = 0.8f;
500 m_VhoverTimescale = 10;
501 m_VehicleBuoyancy = 1;
502
503 m_linearDeflectionEfficiency = 0;
504 m_linearDeflectionTimescale = 5;
505
506 m_angularDeflectionEfficiency = 0;
507 m_angularDeflectionTimescale = 5;
508
509 m_verticalAttractionEfficiency = 1f;
510 m_verticalAttractionTimescale = 100f;
511
512 m_bankingEfficiency = 0;
513 m_bankingMix = 0.7f;
514 m_bankingTimescale = 5;
515
516 m_referenceFrame = Quaternion.Identity;
517
518 m_referenceFrame = Quaternion.Identity;
519 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
520 | VehicleFlag.HOVER_TERRAIN_ONLY
521 | VehicleFlag.HOVER_UP_ONLY
522 | VehicleFlag.NO_DEFLECTION_UP
523 | VehicleFlag.LIMIT_MOTOR_UP);
524 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
525 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
526 break;
527 }
528
529 // Update any physical parameters based on this type.
530 Refresh();
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
548 }
549
550 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle
552 public void Refresh()
553 {
554 if (IsActive)
555 {
556 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass;
558
559 // Friction affects are handled by this vehicle code
560 float friction = 0f;
561 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
562
563 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping;
567 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
568
569 // Vehicles report collision events so we know when it's on the ground
570 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
571
572 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
573 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
574 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
575
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy);
577 BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav);
578
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
581 }
582 else
583 {
584 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
585 }
586 }
587
588 public bool RemoveBodyDependencies(BSPhysObject prim)
589 {
590 // If active, we need to add our properties back when the body is rebuilt.
591 return IsActive;
592 }
593
594 public void RestoreBodyDependencies(BSPhysObject prim)
595 {
596 if (Prim.LocalID != prim.LocalID)
597 {
598 // The call should be on us by our prim. Error if not.
599 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
600 LogHeader, prim.LocalID, Prim.LocalID);
601 return;
602 }
603 Refresh();
604 }
605
606 #region Known vehicle value functions
607 // Vehicle physical parameters that we buffer from constant getting and setting.
608 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
609 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
610 // This does two things: 1) saves continuious calls into unmanaged code, and
611 // 2) signals when a physics property update must happen back to the simulator
612 // to update values modified for the vehicle.
613 private int m_knownChanged;
614 private int m_knownHas;
615 private float m_knownTerrainHeight;
616 private float m_knownWaterLevel;
617 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce;
620 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
624
625 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8;
634
635 private void ForgetKnownVehicleProperties()
636 {
637 m_knownHas = 0;
638 m_knownChanged = 0;
639 }
640 // Push all the changed values back into the physics engine
641 private void PushKnownChanged()
642 {
643 if (m_knownChanged != 0)
644 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition;
647
648 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation;
650
651 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 {
653 Prim.ForceVelocity = m_knownVelocity;
654 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
655 }
656
657 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true);
659
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time.
664 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity);
665 }
666
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
669
670 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator.
672 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
673 }
674 m_knownChanged = 0;
675 }
676
677 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step.
679 private float GetTerrainHeight(Vector3 pos)
680 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
682 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight;
685 }
686 return m_knownTerrainHeight;
687 }
688
689 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step.
691 private float GetWaterLevel(Vector3 pos)
692 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
694 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel;
697 }
698 return (float)m_knownWaterLevel;
699 }
700
701 private Vector3 VehiclePosition
702 {
703 get
704 {
705 if ((m_knownHas & m_knownChangedPosition) == 0)
706 {
707 m_knownPosition = Prim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition;
709 }
710 return m_knownPosition;
711 }
712 set
713 {
714 m_knownPosition = value;
715 m_knownChanged |= m_knownChangedPosition;
716 m_knownHas |= m_knownChangedPosition;
717 }
718 }
719
720 private Quaternion VehicleOrientation
721 {
722 get
723 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 {
726 m_knownOrientation = Prim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation;
728 }
729 return m_knownOrientation;
730 }
731 set
732 {
733 m_knownOrientation = value;
734 m_knownChanged |= m_knownChangedOrientation;
735 m_knownHas |= m_knownChangedOrientation;
736 }
737 }
738
739 private Vector3 VehicleVelocity
740 {
741 get
742 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 {
745 m_knownVelocity = Prim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity;
747 }
748 return (Vector3)m_knownVelocity;
749 }
750 set
751 {
752 m_knownVelocity = value;
753 m_knownChanged |= m_knownChangedVelocity;
754 m_knownHas |= m_knownChangedVelocity;
755 }
756 }
757
758 private void VehicleAddForce(Vector3 aForce)
759 {
760 if ((m_knownHas & m_knownChangedForce) == 0)
761 {
762 m_knownForce = Vector3.Zero;
763 }
764 m_knownForce += aForce;
765 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce;
767 }
768
769 private Vector3 VehicleRotationalVelocity
770 {
771 get
772 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity;
777 }
778 return (Vector3)m_knownRotationalVelocity;
779 }
780 set
781 {
782 m_knownRotationalVelocity = value;
783 m_knownChanged |= m_knownChangedRotationalVelocity;
784 m_knownHas |= m_knownChangedRotationalVelocity;
785 }
786 }
787 private void VehicleAddAngularForce(Vector3 aForce)
788 {
789 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
790 {
791 m_knownRotationalForce = Vector3.Zero;
792 }
793 m_knownRotationalForce += aForce;
794 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce;
796 }
797 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity
799 {
800 get
801 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 }
809 }
810 private float VehicleForwardSpeed
811 {
812 get
813 {
814 return VehicleForwardVelocity.X;
815 }
816 }
817
818 #endregion // Known vehicle value functions
819
820 // One step of the vehicle properties for the next 'pTimestep' seconds.
821 internal void Step(float pTimestep)
822 {
823 if (!IsActive) return;
824
825 ForgetKnownVehicleProperties();
826
827 MoveLinear(pTimestep);
828 MoveAngular(pTimestep);
829
830 LimitRotation(pTimestep);
831
832 // remember the position so next step we can limit absolute movement effects
833 m_lastPositionVector = VehiclePosition;
834
835 // If we forced the changing of some vehicle parameters, update the values and
836 // for the physics engine to note the changes so an UpdateProperties event will happen.
837 PushKnownChanged();
838
839 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
840 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
841 }
842
843 // Apply the effect of the linear motor and other linear motions (like hover and float).
844 private void MoveLinear(float pTimestep)
845 {
846 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
847
848 // The movement computed in the linear motor is relative to the vehicle
849 // coordinates. Rotate the movement to world coordinates.
850 linearMotorContribution *= VehicleOrientation;
851
852 // ==================================================================
853 // Buoyancy: force to overcome gravity.
854 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
855 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
856 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
857
858 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
859
860 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
861
862 ComputeLinearBlockingEndPoint(pTimestep);
863
864 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
865
866 // ==================================================================
867 Vector3 newVelocity = linearMotorContribution
868 + terrainHeightContribution
869 + hoverContribution
870 + limitMotorUpContribution;
871
872 Vector3 newForce = buoyancyContribution;
873
874 // If not changing some axis, reduce out velocity
875 if ((m_flags & (VehicleFlag.NO_X)) != 0)
876 newVelocity.X = 0;
877 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
878 newVelocity.Y = 0;
879 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
880 newVelocity.Z = 0;
881
882 // ==================================================================
883 // Clamp high or low velocities
884 float newVelocityLengthSq = newVelocity.LengthSquared();
885 if (newVelocityLengthSq > 1000f)
886 {
887 newVelocity /= newVelocity.Length();
888 newVelocity *= 1000f;
889 }
890 else if (newVelocityLengthSq < 0.001f)
891 newVelocity = Vector3.Zero;
892
893 // ==================================================================
894 // Stuff new linear velocity into the vehicle.
895 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
896 VehicleVelocity = newVelocity;
897
898 // Other linear forces are applied as forces.
899 Vector3 totalDownForce = newForce * m_vehicleMass;
900 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
901 {
902 VehicleAddForce(totalDownForce);
903 }
904
905 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
906 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
907 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
908 Prim.LocalID,
909 linearMotorContribution, terrainHeightContribution, hoverContribution,
910 limitMotorUpContribution, buoyancyContribution
911 );
912
913 } // end MoveLinear()
914
915 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
916 {
917 Vector3 ret = Vector3.Zero;
918 // If below the terrain, move us above the ground a little.
919 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
920 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
921 {
922 // TODO: correct position by applying force rather than forcing position.
923 Vector3 newPosition = VehiclePosition;
924 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
925 VehiclePosition = newPosition;
926 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
927 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
928 }
929 return ret;
930 }
931
932 public Vector3 ComputeLinearHover(float pTimestep)
933 {
934 Vector3 ret = Vector3.Zero;
935
936 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
937 // m_VhoverTimescale: time to achieve height
938 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
939 {
940 // We should hover, get the target height
941 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
942 {
943 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
944 }
945 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
946 {
947 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
948 }
949 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
950 {
951 m_VhoverTargetHeight = m_VhoverHeight;
952 }
953
954 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
955 {
956 // If body is already heigher, use its height as target height
957 if (VehiclePosition.Z > m_VhoverTargetHeight)
958 m_VhoverTargetHeight = VehiclePosition.Z;
959 }
960
961 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
962 {
963 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
964 {
965 Vector3 pos = VehiclePosition;
966 pos.Z = m_VhoverTargetHeight;
967 VehiclePosition = pos;
968 }
969 }
970 else
971 {
972 // Error is positive if below the target and negative if above.
973 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
974 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
975
976 // TODO: implement m_VhoverEfficiency correctly
977 if (Math.Abs(verticalError) > m_VhoverEfficiency)
978 {
979 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
980 }
981 }
982
983 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
984 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
985 }
986
987 return ret;
988 }
989
990 public bool ComputeLinearBlockingEndPoint(float pTimestep)
991 {
992 bool changed = false;
993
994 Vector3 pos = VehiclePosition;
995 Vector3 posChange = pos - m_lastPositionVector;
996 if (m_BlockingEndPoint != Vector3.Zero)
997 {
998 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
999 {
1000 pos.X -= posChange.X + 1;
1001 changed = true;
1002 }
1003 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1004 {
1005 pos.Y -= posChange.Y + 1;
1006 changed = true;
1007 }
1008 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1009 {
1010 pos.Z -= posChange.Z + 1;
1011 changed = true;
1012 }
1013 if (pos.X <= 0)
1014 {
1015 pos.X += posChange.X + 1;
1016 changed = true;
1017 }
1018 if (pos.Y <= 0)
1019 {
1020 pos.Y += posChange.Y + 1;
1021 changed = true;
1022 }
1023 if (changed)
1024 {
1025 VehiclePosition = pos;
1026 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1027 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
1028 }
1029 }
1030 return changed;
1031 }
1032
1033 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1034 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1035 // used with conjunction with banking: the strength of the banking will decay when the
1036 // vehicle no longer experiences collisions. The decay timescale is the same as
1037 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1038 // when they are in mid jump.
1039 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1040 // This is just using the ground and a general collision check. Should really be using
1041 // a downward raycast to find what is below.
1042 public Vector3 ComputeLinearMotorUp(float pTimestep)
1043 {
1044 Vector3 ret = Vector3.Zero;
1045 float distanceAboveGround = 0f;
1046
1047 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1048 {
1049 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1050 distanceAboveGround = VehiclePosition.Z - targetHeight;
1051 // Not colliding if the vehicle is off the ground
1052 if (!Prim.IsColliding)
1053 {
1054 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1055 ret = new Vector3(0, 0, -distanceAboveGround);
1056 }
1057 // TODO: this calculation is wrong. From the description at
1058 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1059 // has a decay factor. This says this force should
1060 // be computed with a motor.
1061 // TODO: add interaction with banking.
1062 }
1063 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1064 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1065 return ret;
1066 }
1067
1068 // =======================================================================
1069 // =======================================================================
1070 // Apply the effect of the angular motor.
1071 // The 'contribution' is how much angular correction velocity each function wants.
1072 // All the contributions are added together and the resulting velocity is
1073 // set directly on the vehicle.
1074 private void MoveAngular(float pTimestep)
1075 {
1076 // The user wants this many radians per second angular change?
1077 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1078
1079 // ==================================================================
1080 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1081 // This flag prevents linear deflection parallel to world z-axis. This is useful
1082 // for preventing ground vehicles with large linear deflection, like bumper cars,
1083 // from climbing their linear deflection into the sky.
1084 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1085 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1086 {
1087 angularMotorContribution.X = 0f;
1088 angularMotorContribution.Y = 0f;
1089 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1090 }
1091
1092 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1093
1094 Vector3 deflectionContribution = ComputeAngularDeflection();
1095
1096 Vector3 bankingContribution = ComputeAngularBanking();
1097
1098 // ==================================================================
1099 m_lastVertAttractor = verticalAttractionContribution;
1100
1101 m_lastAngularVelocity = angularMotorContribution
1102 + verticalAttractionContribution
1103 + deflectionContribution
1104 + bankingContribution;
1105
1106 // ==================================================================
1107 // Apply the correction velocity.
1108 // TODO: Should this be applied as an angular force (torque)?
1109 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1110 {
1111 VehicleRotationalVelocity = m_lastAngularVelocity;
1112
1113 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1114 Prim.LocalID,
1115 angularMotorContribution, verticalAttractionContribution,
1116 bankingContribution, deflectionContribution,
1117 m_lastAngularVelocity
1118 );
1119 }
1120 else
1121 {
1122 // The vehicle is not adding anything angular wise.
1123 VehicleRotationalVelocity = Vector3.Zero;
1124 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1125 }
1126
1127 // ==================================================================
1128 //Offset section
1129 if (m_linearMotorOffset != Vector3.Zero)
1130 {
1131 //Offset of linear velocity doesn't change the linear velocity,
1132 // but causes a torque to be applied, for example...
1133 //
1134 // IIIII >>> IIIII
1135 // IIIII >>> IIIII
1136 // IIIII >>> IIIII
1137 // ^
1138 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1139 //
1140 //
1141 // The torque created is the linear velocity crossed with the offset
1142
1143 // TODO: this computation should be in the linear section
1144 // because that is where we know the impulse being applied.
1145 Vector3 torqueFromOffset = Vector3.Zero;
1146 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1147 if (float.IsNaN(torqueFromOffset.X))
1148 torqueFromOffset.X = 0;
1149 if (float.IsNaN(torqueFromOffset.Y))
1150 torqueFromOffset.Y = 0;
1151 if (float.IsNaN(torqueFromOffset.Z))
1152 torqueFromOffset.Z = 0;
1153
1154 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1155 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1156 }
1157
1158 }
1159 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1160 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1161 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1162 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1163 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1164 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1165 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1166 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1167 public Vector3 ComputeAngularVerticalAttraction()
1168 {
1169 Vector3 ret = Vector3.Zero;
1170
1171 // If vertical attaction timescale is reasonable
1172 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1173 {
1174 // Take a vector pointing up and convert it from world to vehicle relative coords.
1175 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1176
1177 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1178 // is now:
1179 // leaning to one side: rotated around the X axis with the Y value going
1180 // from zero (nearly straight up) to one (completely to the side)) or
1181 // leaning front-to-back: rotated around the Y axis with the value of X being between
1182 // zero and one.
1183 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1184
1185 // Y error means needed rotation around X axis and visa versa.
1186 // Since the error goes from zero to one, the asin is the corresponding angle.
1187 ret.X = (float)Math.Asin(verticalError.Y);
1188 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1189 ret.Y = -(float)Math.Asin(verticalError.X);
1190
1191 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1192 if (verticalError.Z < 0f)
1193 {
1194 ret.X += PIOverFour;
1195 ret.Y += PIOverFour;
1196 }
1197
1198 // 'ret' is now the necessary velocity to correct tilt in one second.
1199 // Correction happens over a number of seconds.
1200 Vector3 unscaledContrib = ret;
1201 ret /= m_verticalAttractionTimescale;
1202
1203 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1204 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1205 }
1206 return ret;
1207 }
1208
1209 // Return the angular correction to correct the direction the vehicle is pointing to be
1210 // the direction is should want to be pointing.
1211 // The vehicle is moving in some direction and correct its orientation to it is pointing
1212 // in that direction.
1213 // TODO: implement reference frame.
1214 public Vector3 ComputeAngularDeflection()
1215 {
1216 Vector3 ret = Vector3.Zero;
1217 return ret; // DEBUG DEBUG DEBUG
1218 // Disable angular deflection for the moment.
1219 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1220 // approximately the same X or Y correction. When added together (when contributions are combined)
1221 // this creates an over-correction and then wabbling as the target is overshot.
1222 // TODO: rethink how the different correction computations inter-relate.
1223
1224 if (m_angularDeflectionEfficiency != 0)
1225 {
1226 // The direction the vehicle is moving
1227 Vector3 movingDirection = VehicleVelocity;
1228 movingDirection.Normalize();
1229
1230 // The direction the vehicle is pointing
1231 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1232 pointingDirection.Normalize();
1233
1234 // The difference between what is and what should be.
1235 Vector3 deflectionError = movingDirection - pointingDirection;
1236
1237 // Don't try to correct very large errors (not our job)
1238 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1239 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1240 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1241
1242 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1243
1244 // Scale the correction by recovery timescale and efficiency
1245 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1246 ret /= m_angularDeflectionTimescale;
1247
1248 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1249 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1250 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1251 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1252 }
1253 return ret;
1254 }
1255
1256 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1257 // is tipped around the X axis.
1258 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1259 // The vertical attractor feature must be enabled in order for the banking behavior to
1260 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1261 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1262 // of the yaw effect will be proportional to the
1263 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1264 // velocity along its preferred axis of motion.
1265 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1266 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1267 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1268 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1269 // Negating the banking coefficient will make it so that the vehicle leans to the
1270 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1271 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1272 // banking vehicles do what you want rather than what the laws of physics allow.
1273 // For example, consider a real motorcycle...it must be moving forward in order for
1274 // it to turn while banking, however video-game motorcycles are often configured
1275 // to turn in place when at a dead stop--because they are often easier to control
1276 // that way using the limited interface of the keyboard or game controller. The
1277 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1278 // banking by functioning as a slider between a banking that is correspondingly
1279 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1280 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1281 // to "dynamic" where the banking is also proportional to its velocity along its
1282 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1283 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1284 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1285 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1286 // make a sluggish vehicle by giving it a timescale of several seconds.
1287 public Vector3 ComputeAngularBanking()
1288 {
1289 Vector3 ret = Vector3.Zero;
1290
1291 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1292 {
1293 // This works by rotating a unit vector to the orientation of the vehicle. The
1294 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1295 // up to one for full over).
1296 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1297
1298 // Figure out the yaw value for this much roll.
1299 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1300 // Keep the sign
1301 if (rollComponents.Y < 0f)
1302 turnComponent = -turnComponent;
1303
1304 // TODO: there must be a better computation of the banking force.
1305 float bankingTurnForce = turnComponent;
1306
1307 // actual error = static turn error + dynamic turn error
1308 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1309 // TODO: the banking effect should not go to infinity but what to limit it to?
1310 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1311
1312 // Build the force vector to change rotation from what it is to what it should be
1313 ret.Z = -mixedBankingError;
1314
1315 // Don't do it all at once.
1316 ret /= m_bankingTimescale;
1317
1318 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1319 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1320 }
1321 return ret;
1322 }
1323
1324 // This is from previous instantiations of XXXDynamics.cs.
1325 // Applies roll reference frame.
1326 // TODO: is this the right way to separate the code to do this operation?
1327 // Should this be in MoveAngular()?
1328 internal void LimitRotation(float timestep)
1329 {
1330 Quaternion rotq = VehicleOrientation;
1331 Quaternion m_rot = rotq;
1332 if (m_RollreferenceFrame != Quaternion.Identity)
1333 {
1334 if (rotq.X >= m_RollreferenceFrame.X)
1335 {
1336 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1337 }
1338 if (rotq.Y >= m_RollreferenceFrame.Y)
1339 {
1340 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1341 }
1342 if (rotq.X <= -m_RollreferenceFrame.X)
1343 {
1344 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1345 }
1346 if (rotq.Y <= -m_RollreferenceFrame.Y)
1347 {
1348 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1349 }
1350 }
1351 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1352 {
1353 m_rot.X = 0;
1354 m_rot.Y = 0;
1355 }
1356 if (rotq != m_rot)
1357 {
1358 VehicleOrientation = m_rot;
1359 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1360 }
1361
1362 }
1363
1364 private float ClampInRange(float low, float val, float high)
1365 {
1366 return Math.Max(low, Math.Min(val, high));
1367 // return Utils.Clamp(val, low, high);
1368 }
1369
1370 // Invoke the detailed logger and output something if it's enabled.
1371 private void VDetailLog(string msg, params Object[] args)
1372 {
1373 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1374 Prim.PhysicsScene.DetailLog(msg, args);
1375 }
1376 }
1377}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs
new file mode 100644
index 0000000..845a113
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs
@@ -0,0 +1,329 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
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
44public abstract class BSLinkset
45{
46 // private static string LogHeader = "[BULLETSIM LINKSET]";
47
48 public enum LinksetImplementation
49 {
50 Constraint = 0, // linkset tied together with constraints
51 Compound = 1, // linkset tied together as a compound object
52 Manual = 2 // linkset tied together manually (code moves all the pieces)
53 }
54 // Create the correct type of linkset for this child
55 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
56 {
57 BSLinkset ret = null;
58
59 switch ((int)BSParam.LinksetImplementation)
60 {
61 case (int)LinksetImplementation.Constraint:
62 ret = new BSLinksetConstraints(physScene, parent);
63 break;
64 case (int)LinksetImplementation.Compound:
65 ret = new BSLinksetCompound(physScene, parent);
66 break;
67 case (int)LinksetImplementation.Manual:
68 // ret = new BSLinksetManual(physScene, parent);
69 break;
70 default:
71 ret = new BSLinksetCompound(physScene, parent);
72 break;
73 }
74 return ret;
75 }
76
77 public BSPhysObject LinksetRoot { get; protected set; }
78
79 public BSScene PhysicsScene { get; private set; }
80
81 static int m_nextLinksetID = 1;
82 public int LinksetID { get; private set; }
83
84 // The children under the root in this linkset.
85 protected HashSet<BSPhysObject> m_children;
86
87 // We lock the diddling of linkset classes to prevent any badness.
88 // This locks the modification of the instances of this class. Changes
89 // to the physical representation is done via the tainting mechenism.
90 protected object m_linksetActivityLock = new Object();
91
92 // Some linksets have a preferred physical shape.
93 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
94 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
95 {
96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
97 }
98
99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
100 public float LinksetMass { get; protected set; }
101
102 public virtual bool LinksetIsColliding { get { return false; } }
103
104 public OMV.Vector3 CenterOfMass
105 {
106 get { return ComputeLinksetCenterOfMass(); }
107 }
108
109 public OMV.Vector3 GeometricCenter
110 {
111 get { return ComputeLinksetGeometricCenter(); }
112 }
113
114 protected BSLinkset(BSScene scene, BSPhysObject parent)
115 {
116 // A simple linkset of one (no children)
117 LinksetID = m_nextLinksetID++;
118 // We create LOTS of linksets.
119 if (m_nextLinksetID <= 0)
120 m_nextLinksetID = 1;
121 PhysicsScene = scene;
122 LinksetRoot = parent;
123 m_children = new HashSet<BSPhysObject>();
124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
126 }
127
128 // Link to a linkset where the child knows the parent.
129 // Parent changing should not happen so do some sanity checking.
130 // We return the parent's linkset so the child can track its membership.
131 // Called at runtime.
132 public BSLinkset AddMeToLinkset(BSPhysObject child)
133 {
134 lock (m_linksetActivityLock)
135 {
136 // Don't add the root to its own linkset
137 if (!IsRoot(child))
138 AddChildToLinkset(child);
139 LinksetMass = ComputeLinksetMass();
140 }
141 return this;
142 }
143
144 // Remove a child from a linkset.
145 // Returns a new linkset for the child which is a linkset of one (just the
146 // orphened child).
147 // Called at runtime.
148 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
149 {
150 lock (m_linksetActivityLock)
151 {
152 if (IsRoot(child))
153 {
154 // Cannot remove the root from a linkset.
155 return this;
156 }
157 RemoveChildFromLinkset(child);
158 LinksetMass = ComputeLinksetMass();
159 }
160
161 // The child is down to a linkset of just itself
162 return BSLinkset.Factory(PhysicsScene, child);
163 }
164
165 // Return 'true' if the passed object is the root object of this linkset
166 public bool IsRoot(BSPhysObject requestor)
167 {
168 return (requestor.LocalID == LinksetRoot.LocalID);
169 }
170
171 public int NumberOfChildren { get { return m_children.Count; } }
172
173 // Return 'true' if this linkset has any children (more than the root member)
174 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
175
176 // Return 'true' if this child is in this linkset
177 public bool HasChild(BSPhysObject child)
178 {
179 bool ret = false;
180 lock (m_linksetActivityLock)
181 {
182 ret = m_children.Contains(child);
183 /* Safer version but the above should work
184 foreach (BSPhysObject bp in m_children)
185 {
186 if (child.LocalID == bp.LocalID)
187 {
188 ret = true;
189 break;
190 }
191 }
192 */
193 }
194 return ret;
195 }
196
197 // Perform an action on each member of the linkset including root prim.
198 // Depends on the action on whether this should be done at taint time.
199 public delegate bool ForEachMemberAction(BSPhysObject obj);
200 public virtual bool ForEachMember(ForEachMemberAction action)
201 {
202 bool ret = false;
203 lock (m_linksetActivityLock)
204 {
205 action(LinksetRoot);
206 foreach (BSPhysObject po in m_children)
207 {
208 if (action(po))
209 break;
210 }
211 }
212 return ret;
213 }
214
215 // I am the root of a linkset and a new child is being added
216 // Called while LinkActivity is locked.
217 protected abstract void AddChildToLinkset(BSPhysObject child);
218
219 // I am the root of a linkset and one of my children is being removed.
220 // Safe to call even if the child is not really in my linkset.
221 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
222
223 // When physical properties are changed the linkset needs to recalculate
224 // its internal properties.
225 // May be called at runtime or taint-time.
226 public virtual void Refresh(BSPhysObject requestor)
227 {
228 LinksetMass = ComputeLinksetMass();
229 }
230
231 // Flag denoting the linkset is in the process of being rebuilt.
232 // Used to know not the schedule a rebuild in the middle of a rebuild.
233 protected bool Rebuilding { get; set; }
234
235 // The object is going dynamic (physical). Do any setup necessary
236 // for a dynamic linkset.
237 // Only the state of the passed object can be modified. The rest of the linkset
238 // has not yet been fully constructed.
239 // Return 'true' if any properties updated on the passed object.
240 // Called at taint-time!
241 public abstract bool MakeDynamic(BSPhysObject child);
242
243 // The object is going static (non-physical). Do any setup necessary
244 // for a static linkset.
245 // Return 'true' if any properties updated on the passed object.
246 // Called at taint-time!
247 public abstract bool MakeStatic(BSPhysObject child);
248
249 // Called when a parameter update comes from the physics engine for any object
250 // of the linkset is received.
251 // Passed flag is update came from physics engine (true) or the user (false).
252 // Called at taint-time!!
253 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
254
255 // Routine used when rebuilding the body of the root of the linkset
256 // Destroy all the constraints have have been made to root.
257 // This is called when the root body is changing.
258 // Returns 'true' of something was actually removed and would need restoring
259 // Called at taint-time!!
260 public abstract bool RemoveBodyDependencies(BSPrim child);
261
262 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
263 // this routine will restore the removed constraints.
264 // Called at taint-time!!
265 public abstract void RestoreBodyDependencies(BSPrim child);
266
267 // ================================================================
268 protected virtual float ComputeLinksetMass()
269 {
270 float mass = LinksetRoot.RawMass;
271 if (HasAnyChildren)
272 {
273 lock (m_linksetActivityLock)
274 {
275 foreach (BSPhysObject bp in m_children)
276 {
277 mass += bp.RawMass;
278 }
279 }
280 }
281 return mass;
282 }
283
284 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
285 {
286 OMV.Vector3 com;
287 lock (m_linksetActivityLock)
288 {
289 com = LinksetRoot.Position * LinksetRoot.RawMass;
290 float totalMass = LinksetRoot.RawMass;
291
292 foreach (BSPhysObject bp in m_children)
293 {
294 com += bp.Position * bp.RawMass;
295 totalMass += bp.RawMass;
296 }
297 if (totalMass != 0f)
298 com /= totalMass;
299 }
300
301 return com;
302 }
303
304 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
305 {
306 OMV.Vector3 com;
307 lock (m_linksetActivityLock)
308 {
309 com = LinksetRoot.Position;
310
311 foreach (BSPhysObject bp in m_children)
312 {
313 com += bp.Position * bp.RawMass;
314 }
315 com /= (m_children.Count + 1);
316 }
317
318 return com;
319 }
320
321 // Invoke the detailed logger and output something if it's enabled.
322 protected void DetailLog(string msg, params Object[] args)
323 {
324 if (PhysicsScene.PhysicsLogging.Enabled)
325 PhysicsScene.DetailLog(msg, args);
326 }
327
328}
329}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
new file mode 100644
index 0000000..9a977e6
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
@@ -0,0 +1,397 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
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
67public sealed class BSLinksetCompound : BSLinkset
68{
69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
70
71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
72 {
73 }
74
75 // For compound implimented linksets, if there are children, use compound shape for the root.
76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
77 {
78 // Returning 'unknown' means we don't have a preference.
79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
80 if (IsRoot(requestor) && HasAnyChildren)
81 {
82 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
83 }
84 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
85 return ret;
86 }
87
88 // When physical properties are changed the linkset needs to recalculate
89 // its internal properties.
90 public override void Refresh(BSPhysObject requestor)
91 {
92 base.Refresh(requestor);
93
94 // Something changed so do the rebuilding thing
95 // ScheduleRebuild();
96 }
97
98 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPhysObject requestor)
100 {
101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1}",
102 requestor.LocalID, Rebuilding);
103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild.
105 if (!Rebuilding)
106 {
107 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
108 {
109 if (HasAnyChildren)
110 RecomputeLinksetCompound();
111 });
112 }
113 }
114
115 // The object is going dynamic (physical). Do any setup necessary
116 // for a dynamic linkset.
117 // Only the state of the passed object can be modified. The rest of the linkset
118 // has not yet been fully constructed.
119 // Return 'true' if any properties updated on the passed object.
120 // Called at taint-time!
121 public override bool MakeDynamic(BSPhysObject child)
122 {
123 bool ret = false;
124 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
125 if (IsRoot(child))
126 {
127 // The root is going dynamic. Make sure mass is properly set.
128 ScheduleRebuild(LinksetRoot);
129 }
130 else
131 {
132 // The origional prims are removed from the world as the shape of the root compound
133 // shape takes over.
134 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
135 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
138
139 child.PhysBody.collisionType = CollisionType.LinksetChild;
140
141 ret = true;
142 }
143 return ret;
144 }
145
146 // The object is going static (non-physical). Do any setup necessary for a static linkset.
147 // Return 'true' if any properties updated on the passed object.
148 // This doesn't normally happen -- OpenSim removes the objects from the physical
149 // world if it is a static linkset.
150 // Called at taint-time!
151 public override bool MakeStatic(BSPhysObject child)
152 {
153 bool ret = false;
154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
155 if (IsRoot(child))
156 {
157 ScheduleRebuild(LinksetRoot);
158 }
159 else
160 {
161 // The non-physical children can come back to life.
162 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
166 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
167 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
168 ret = true;
169 }
170 return ret;
171 }
172
173 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
174 {
175 // The user moving a child around requires the rebuilding of the linkset compound shape
176 // One problem is this happens when a border is crossed -- the simulator implementation
177 // is to store the position into the group which causes the move of the object
178 // but it also means all the child positions get updated.
179 // What would cause an unnecessary rebuild so we make sure the linkset is in a
180 // region before bothering to do a rebuild.
181 if (!IsRoot(updated)
182 && !physicalUpdate
183 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
184 {
185 updated.LinksetInfo = null;
186 ScheduleRebuild(updated);
187 }
188 }
189
190 // Routine called when rebuilding the body of some member of the linkset.
191 // Since we don't keep in world relationships, do nothing unless it's a child changing.
192 // Returns 'true' of something was actually removed and would need restoring
193 // Called at taint-time!!
194 public override bool RemoveBodyDependencies(BSPrim child)
195 {
196 bool ret = false;
197
198 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
199 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), IsRoot(child));
200
201 if (!IsRoot(child))
202 {
203 // Because it is a convenient time, recompute child world position and rotation based on
204 // its position in the linkset.
205 RecomputeChildWorldPosition(child, true);
206 }
207
208 // Cannot schedule a refresh/rebuild here because this routine is called when
209 // the linkset is being rebuilt.
210 // InternalRefresh(LinksetRoot);
211
212 return ret;
213 }
214
215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
216 // this routine will restore the removed constraints.
217 // Called at taint-time!!
218 public override void RestoreBodyDependencies(BSPrim child)
219 {
220 }
221
222 // When the linkset is built, the child shape is added to the compound shape relative to the
223 // root shape. The linkset then moves around but this does not move the actual child
224 // prim. The child prim's location must be recomputed based on the location of the root shape.
225 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
226 {
227 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
228 if (lci != null)
229 {
230 if (inTaintTime)
231 {
232 OMV.Vector3 oldPos = child.RawPosition;
233 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
234 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
235 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
236 child.LocalID, oldPos, lci, child.RawPosition);
237 }
238 else
239 {
240 // TaintedObject is not used here so the raw position is set now and not at taint-time.
241 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
242 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
243 }
244 }
245 else
246 {
247 // This happens when children have been added to the linkset but the linkset
248 // has not been constructed yet. So like, at taint time, adding children to a linkset
249 // and then changing properties of the children (makePhysical, for instance)
250 // but the post-print action of actually rebuilding the linkset has not yet happened.
251 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
252 // LogHeader, child.LocalID);
253 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
254 }
255 }
256
257 // ================================================================
258
259 // Add a new child to the linkset.
260 // Called while LinkActivity is locked.
261 protected override void AddChildToLinkset(BSPhysObject child)
262 {
263 if (!HasChild(child))
264 {
265 m_children.Add(child);
266
267 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
268
269 // Rebuild the compound shape with the new child shape included
270 ScheduleRebuild(child);
271 }
272 return;
273 }
274
275 // Remove the specified child from the linkset.
276 // Safe to call even if the child is not really in the linkset.
277 protected override void RemoveChildFromLinkset(BSPhysObject child)
278 {
279 if (m_children.Remove(child))
280 {
281 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
282 child.LocalID,
283 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(),
284 child.LocalID, child.PhysBody.ptr.ToString());
285
286 // Cause the child's body to be rebuilt and thus restored to normal operation
287 RecomputeChildWorldPosition(child, false);
288 child.ForceBodyShapeRebuild(false);
289
290 if (!HasAnyChildren)
291 {
292 // The linkset is now empty. The root needs rebuilding.
293 LinksetRoot.ForceBodyShapeRebuild(false);
294 }
295 else
296 {
297 // Rebuild the compound shape with the child removed
298 ScheduleRebuild(child);
299 }
300 }
301 return;
302 }
303
304 // Called before the simulation step to make sure the compound based linkset
305 // is all initialized.
306 // Constraint linksets are rebuilt every time.
307 // Note that this works for rebuilding just the root after a linkset is taken apart.
308 // Called at taint time!!
309 private void RecomputeLinksetCompound()
310 {
311 try
312 {
313 // Suppress rebuilding while rebuilding
314 Rebuilding = true;
315
316 // Cause the root shape to be rebuilt as a compound object with just the root in it
317 LinksetRoot.ForceBodyShapeRebuild(true);
318
319 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
320 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
321
322 // Add a shape for each of the other children in the linkset
323 ForEachMember(delegate(BSPhysObject cPrim)
324 {
325 if (!IsRoot(cPrim))
326 {
327 // Compute the displacement of the child from the root of the linkset.
328 // This info is saved in the child prim so the relationship does not
329 // change over time and the new child position can be computed
330 // when the linkset is being disassembled (the linkset may have moved).
331 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
332 if (lci == null)
333 {
334 // Each child position and rotation is given relative to the root.
335 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
336 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
337 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
338
339 // Save relative position for recomputing child's world position after moving linkset.
340 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
341 cPrim.LinksetInfo = lci;
342 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
343 }
344
345 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
346 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
347
348 if (cPrim.PhysShape.isNativeShape)
349 {
350 // A native shape is turning into a hull collision shape because native
351 // shapes are not shared so we have to hullify it so it will be tracked
352 // and freed at the correct time. This also solves the scaling problem
353 // (native shapes scaled but hull/meshes are assumed to not be).
354 // TODO: decide of the native shape can just be used in the compound shape.
355 // Use call to CreateGeomNonSpecial().
356 BulletShape saveShape = cPrim.PhysShape;
357 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
358 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
359 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
360 BulletShape newShape = cPrim.PhysShape;
361 cPrim.PhysShape = saveShape;
362 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
363 }
364 else
365 {
366 // For the shared shapes (meshes and hulls), just use the shape in the child.
367 // The reference count added here will be decremented when the compound shape
368 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
369 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
372 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
373 }
374 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
375 }
376 }
377 return false; // 'false' says to move onto the next child in the list
378 });
379
380 // With all of the linkset packed into the root prim, it has the mass of everyone.
381 LinksetMass = LinksetMass;
382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
383 }
384 finally
385 {
386 Rebuilding = false;
387 }
388
389 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
390
391 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
392 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
393 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
394
395 }
396}
397} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
new file mode 100644
index 0000000..46ff99f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,316 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 {
41 }
42
43 // When physical properties are changed the linkset needs to recalculate
44 // its internal properties.
45 // This is queued in the 'post taint' queue so the
46 // refresh will happen once after all the other taints are applied.
47 public override void Refresh(BSPhysObject requestor)
48 {
49 base.Refresh(requestor);
50
51 // Queue to happen after all the other taint processing
52 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
53 {
54 if (HasAnyChildren && IsRoot(requestor))
55 RecomputeLinksetConstraints();
56 });
57 }
58
59 // The object is going dynamic (physical). Do any setup necessary
60 // for a dynamic linkset.
61 // Only the state of the passed object can be modified. The rest of the linkset
62 // has not yet been fully constructed.
63 // Return 'true' if any properties updated on the passed object.
64 // Called at taint-time!
65 public override bool MakeDynamic(BSPhysObject child)
66 {
67 // What is done for each object in BSPrim is what we want.
68 return false;
69 }
70
71 // The object is going static (non-physical). Do any setup necessary for a static linkset.
72 // Return 'true' if any properties updated on the passed object.
73 // This doesn't normally happen -- OpenSim removes the objects from the physical
74 // world if it is a static linkset.
75 // Called at taint-time!
76 public override bool MakeStatic(BSPhysObject child)
77 {
78 // What is done for each object in BSPrim is what we want.
79 return false;
80 }
81
82 // Called at taint-time!!
83 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
84 {
85 // Nothing to do for constraints on property updates
86 }
87
88 // Routine called when rebuilding the body of some member of the linkset.
89 // Destroy all the constraints have have been made to root and set
90 // up to rebuild the constraints before the next simulation step.
91 // Returns 'true' of something was actually removed and would need restoring
92 // Called at taint-time!!
93 public override bool RemoveBodyDependencies(BSPrim child)
94 {
95 bool ret = false;
96
97 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
98 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString());
99
100 lock (m_linksetActivityLock)
101 {
102 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
103 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
104 // Cause the constraints, et al to be rebuilt before the next simulation step.
105 Refresh(LinksetRoot);
106 }
107 return ret;
108 }
109
110 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
111 // this routine will restore the removed constraints.
112 // Called at taint-time!!
113 public override void RestoreBodyDependencies(BSPrim child)
114 {
115 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
116 }
117
118 // ================================================================
119
120 // Add a new child to the linkset.
121 // Called while LinkActivity is locked.
122 protected override void AddChildToLinkset(BSPhysObject child)
123 {
124 if (!HasChild(child))
125 {
126 m_children.Add(child);
127
128 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
129
130 // Cause constraints and assorted properties to be recomputed before the next simulation step.
131 Refresh(LinksetRoot);
132 }
133 return;
134 }
135
136 // Remove the specified child from the linkset.
137 // Safe to call even if the child is not really in my linkset.
138 protected override void RemoveChildFromLinkset(BSPhysObject child)
139 {
140 if (m_children.Remove(child))
141 {
142 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
143 BSPhysObject childx = child;
144
145 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
146 childx.LocalID,
147 rootx.LocalID, rootx.PhysBody.ptr.ToString(),
148 childx.LocalID, childx.PhysBody.ptr.ToString());
149
150 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
151 {
152 PhysicallyUnlinkAChildFromRoot(rootx, childx);
153 });
154 // See that the linkset parameters are recomputed at the end of the taint time.
155 Refresh(LinksetRoot);
156 }
157 else
158 {
159 // Non-fatal occurance.
160 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
161 }
162 return;
163 }
164
165 // Create a constraint between me (root of linkset) and the passed prim (the child).
166 // Called at taint time!
167 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
168 {
169 // Don't build the constraint when asked. Put it off until just before the simulation step.
170 Refresh(rootPrim);
171 }
172
173 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
174 {
175 // Zero motion for children so they don't interpolate
176 childPrim.ZeroMotion(true);
177
178 // Relative position normalized to the root prim
179 // Essentually a vector pointing from center of rootPrim to center of childPrim
180 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
181
182 // real world coordinate of midpoint between the two objects
183 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
184
185 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
186 rootPrim.LocalID,
187 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
188 childPrim.LocalID, childPrim.PhysBody.ptr.ToString(),
189 rootPrim.Position, childPrim.Position, midPoint);
190
191 // create a constraint that allows no freedom of movement between the two objects
192 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
193
194 BSConstraint6Dof constrain = new BSConstraint6Dof(
195 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
196 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
197
198 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
199 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
200 * of the objects.
201 * Code left for future programmers.
202 // ==================================================================================
203 // relative position normalized to the root prim
204 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
205 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
206
207 // relative rotation of the child to the parent
208 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
209 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
210
211 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
212 BS6DofConstraint constrain = new BS6DofConstraint(
213 PhysicsScene.World, rootPrim.Body, childPrim.Body,
214 OMV.Vector3.Zero,
215 OMV.Quaternion.Inverse(rootPrim.Orientation),
216 OMV.Vector3.Zero,
217 OMV.Quaternion.Inverse(childPrim.Orientation),
218 true,
219 true
220 );
221 // ==================================================================================
222 */
223
224 PhysicsScene.Constraints.AddConstraint(constrain);
225
226 // zero linear and angular limits makes the objects unable to move in relation to each other
227 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
228 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
229
230 // tweek the constraint to increase stability
231 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
232 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
233 BSParam.LinkConstraintTransMotorMaxVel,
234 BSParam.LinkConstraintTransMotorMaxForce);
235 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
236 if (BSParam.LinkConstraintSolverIterations != 0f)
237 {
238 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
239 }
240 return constrain;
241 }
242
243 // Remove linkage between the linkset root and a particular child
244 // The root and child bodies are passed in because we need to remove the constraint between
245 // the bodies that were present at unlink time.
246 // Called at taint time!
247 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
248 {
249 bool ret = false;
250 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
251 rootPrim.LocalID,
252 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
253 childPrim.LocalID, childPrim.PhysBody.ptr.ToString());
254
255 // Find the constraint for this link and get rid of it from the overall collection and from my list
256 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
257 {
258 // Make the child refresh its location
259 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
260 ret = true;
261 }
262
263 return ret;
264 }
265
266 // Remove linkage between myself and any possible children I might have.
267 // Returns 'true' of any constraints were destroyed.
268 // Called at taint time!
269 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
270 {
271 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
272
273 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
274 }
275
276 // Call each of the constraints that make up this linkset and recompute the
277 // various transforms and variables. Create constraints of not created yet.
278 // Called before the simulation step to make sure the constraint based linkset
279 // is all initialized.
280 // Called at taint time!!
281 private void RecomputeLinksetConstraints()
282 {
283 float linksetMass = LinksetMass;
284 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
285
286 // DEBUG: see of inter-linkset collisions are causing problems
287 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
288 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
290 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), linksetMass);
291
292 foreach (BSPhysObject child in m_children)
293 {
294 // A child in the linkset physically shows the mass of the whole linkset.
295 // This allows Bullet to apply enough force on the child to move the whole linkset.
296 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
297 child.UpdatePhysicalMassProperties(linksetMass, true);
298
299 BSConstraint constrain;
300 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
301 {
302 // If constraint doesn't exist yet, create it.
303 constrain = BuildConstraint(LinksetRoot, child);
304 }
305 constrain.RecomputeConstraintVariables(linksetMass);
306
307 // DEBUG: see of inter-linkset collisions are causing problems
308 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
309 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
310
311 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
312 }
313
314 }
315}
316}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs
new file mode 100644
index 0000000..d7941b6
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/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.BulletSNPlugin
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",3.5f, 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.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 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",3.5f, 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/BulletSNPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs
new file mode 100644
index 0000000..7abc9b2
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs
@@ -0,0 +1,347 @@
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.Text;
31using OpenMetaverse;
32using OpenSim.Framework;
33
34namespace OpenSim.Region.Physics.BulletSNPlugin
35{
36public abstract class BSMotor
37{
38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 public const float Infinite = 12345.6f;
40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41
42 public BSMotor(string useName)
43 {
44 UseName = useName;
45 PhysicsScene = null;
46 Enabled = true;
47 }
48 public virtual bool Enabled { get; set; }
49 public virtual void Reset() { }
50 public virtual void Zero() { }
51 public virtual void GenerateTestOutput(float timeStep) { }
52
53 // A name passed at motor creation for easily identifyable debugging messages.
54 public string UseName { get; private set; }
55
56 // Used only for outputting debug information. Might not be set so check for null.
57 public BSScene PhysicsScene { get; set; }
58 protected void MDetailLog(string msg, params Object[] parms)
59 {
60 if (PhysicsScene != null)
61 {
62 if (PhysicsScene.VehicleLoggingEnabled)
63 {
64 PhysicsScene.DetailLog(msg, parms);
65 }
66 }
67 }
68}
69
70// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
71// The TargetValue decays in TargetValueDecayTimeScale and
72// the CurrentValue will be held back by FrictionTimeScale.
73// This motor will "zero itself" over time in that the targetValue will
74// decay to zero and the currentValue will follow it to that zero.
75// The overall effect is for the returned correction value to go from large
76// values (the total difference between current and target minus friction)
77// to small and eventually zero values.
78// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
79
80// For instance, if something is moving at speed X and the desired speed is Y,
81// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
82// values of CurrentValue are returned that approach the TargetValue.
83// The feature of decaying TargetValue is so vehicles will eventually
84// come to a stop rather than run forever. This can be disabled by
85// setting TargetValueDecayTimescale to 'infinite'.
86// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
87public class BSVMotor : BSMotor
88{
89 // public Vector3 FrameOfReference { get; set; }
90 // public Vector3 Offset { get; set; }
91
92 public virtual float TimeScale { get; set; }
93 public virtual float TargetValueDecayTimeScale { get; set; }
94 public virtual Vector3 FrictionTimescale { get; set; }
95 public virtual float Efficiency { get; set; }
96
97 public virtual float ErrorZeroThreshold { get; set; }
98
99 public virtual Vector3 TargetValue { get; protected set; }
100 public virtual Vector3 CurrentValue { get; protected set; }
101 public virtual Vector3 LastError { get; protected set; }
102
103 public virtual bool ErrorIsZero
104 { get {
105 return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold);
106 }
107 }
108
109 public BSVMotor(string useName)
110 : base(useName)
111 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f;
117 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
119 : this(useName)
120 {
121 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero;
126 }
127 public void SetCurrent(Vector3 current)
128 {
129 CurrentValue = current;
130 }
131 public void SetTarget(Vector3 target)
132 {
133 TargetValue = target;
134 }
135 public override void Zero()
136 {
137 base.Zero();
138 CurrentValue = TargetValue = Vector3.Zero;
139 }
140
141 // Compute the next step and return the new current value
142 public virtual Vector3 Step(float timeStep)
143 {
144 if (!Enabled) return TargetValue;
145
146 Vector3 origTarget = TargetValue; // DEBUG
147 Vector3 origCurrVal = CurrentValue; // DEBUG
148
149 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue;
151 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
152 {
153 correction = Step(timeStep, error);
154
155 CurrentValue += correction;
156
157 // The desired value reduces to zero which also reduces the difference with current.
158 // If the decay time is infinite, don't decay at all.
159 float decayFactor = 0f;
160 if (TargetValueDecayTimeScale != BSMotor.Infinite)
161 {
162 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
163 TargetValue *= (1f - decayFactor);
164 }
165
166 // The amount we can correct the error is reduced by the friction
167 Vector3 frictionFactor = Vector3.Zero;
168 if (FrictionTimescale != BSMotor.InfiniteVector)
169 {
170 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
171 // Individual friction components can be 'infinite' so compute each separately.
172 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
173 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
174 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
175 frictionFactor *= timeStep;
176 CurrentValue *= (Vector3.One - frictionFactor);
177 }
178
179 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
183 BSScene.DetailLogZero, UseName,
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 }
187 else
188 {
189 // Difference between what we have and target is small. Motor is done.
190 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
193 }
194
195 return CurrentValue;
196 }
197 public virtual Vector3 Step(float timeStep, Vector3 error)
198 {
199 if (!Enabled) return Vector3.Zero;
200
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero;
203 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
204 {
205 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount;
207 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
208 correctionAmount = error * timeStep;
209 else
210 correctionAmount = error / TimeScale * timeStep;
211
212 returnCorrection = correctionAmount;
213 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
214 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
215 }
216 return returnCorrection;
217 }
218
219 // The user sets all the parameters and calls this which outputs values until error is zero.
220 public override void GenerateTestOutput(float timeStep)
221 {
222 // maximum number of outputs to generate.
223 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
225 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
226 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
228 CurrentValue, TargetValue);
229
230 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
232 {
233 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238
239
240 }
241
242 public override string ToString()
243 {
244 return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
245 UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
246 }
247}
248
249public class BSFMotor : BSMotor
250{
251 public float TimeScale { get; set; }
252 public float DecayTimeScale { get; set; }
253 public float Friction { get; set; }
254 public float Efficiency { get; set; }
255
256 public float Target { get; private set; }
257 public float CurrentValue { get; private set; }
258
259 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
260 : base(useName)
261 {
262 }
263 public void SetCurrent(float target)
264 {
265 }
266 public void SetTarget(float target)
267 {
268 }
269 public virtual float Step(float timeStep)
270 {
271 return 0f;
272 }
273}
274
275// Proportional, Integral, Derivitive Motor
276// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
277public class BSPIDVMotor : BSVMotor
278{
279 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
280 public Vector3 proportionFactor { get; set; }
281 public Vector3 integralFactor { get; set; }
282 public Vector3 derivFactor { get; set; }
283
284 // Arbritrary factor range.
285 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
286 public float EfficiencyHigh = 0.4f;
287 public float EfficiencyLow = 4.0f;
288
289 // Running integration of the error
290 Vector3 RunningIntegration { get; set; }
291
292 public BSPIDVMotor(string useName)
293 : base(useName)
294 {
295 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
296 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
297 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
298 RunningIntegration = Vector3.Zero;
299 LastError = Vector3.Zero;
300 }
301
302 public override void Zero()
303 {
304 base.Zero();
305 }
306
307 public override float Efficiency
308 {
309 get { return base.Efficiency; }
310 set
311 {
312 base.Efficiency = Util.Clamp(value, 0f, 1f);
313 // Compute factors based on efficiency.
314 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
315 // If efficiency is low (0f), use a factor value that overcorrects.
316 // TODO: might want to vary contribution of different factor depending on efficiency.
317 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
318 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
319 proportionFactor = new Vector3(factor, factor, factor);
320 integralFactor = new Vector3(factor, factor, factor);
321 derivFactor = new Vector3(factor, factor, factor);
322 }
323 }
324
325 // Ignore Current and Target Values and just advance the PID computation on this error.
326 public override Vector3 Step(float timeStep, Vector3 error)
327 {
328 if (!Enabled) return Vector3.Zero;
329
330 // Add up the error so we can integrate over the accumulated errors
331 RunningIntegration += error * timeStep;
332
333 // A simple derivitive is the rate of change from the last error.
334 Vector3 derivFactor = (error - LastError) * timeStep;
335 LastError = error;
336
337 // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
338 Vector3 ret = -(
339 error * proportionFactor
340 + RunningIntegration * integralFactor
341 + derivFactor * derivFactor
342 );
343
344 return ret;
345 }
346}
347}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs
new file mode 100644
index 0000000..5e93a03
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs
@@ -0,0 +1,559 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSNPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48
49 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; }
51 public static float DeactivationTime { get; private set; }
52 public static float LinearSleepingThreshold { get; private set; }
53 public static float AngularSleepingThreshold { get; private set; }
54 public static float CcdMotionThreshold { get; private set; }
55 public static float CcdSweptSphereRadius { get; private set; }
56 public static float ContactProcessingThreshold { get; private set; }
57
58 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
59 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
60 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
61
62 public static float TerrainImplementation { get; private set; }
63 public static float TerrainFriction { get; private set; }
64 public static float TerrainHitFraction { get; private set; }
65 public static float TerrainRestitution { get; private set; }
66 public static float TerrainCollisionMargin { get; private set; }
67
68 // Avatar parameters
69 public static float AvatarFriction { get; private set; }
70 public static float AvatarStandingFriction { get; private set; }
71 public static float AvatarDensity { get; private set; }
72 public static float AvatarRestitution { get; private set; }
73 public static float AvatarCapsuleWidth { get; private set; }
74 public static float AvatarCapsuleDepth { get; private set; }
75 public static float AvatarCapsuleHeight { get; private set; }
76 public static float AvatarContactProcessingThreshold { get; private set; }
77
78 public static float VehicleAngularDamping { get; private set; }
79
80 public static float LinksetImplementation { get; private set; }
81 public static float LinkConstraintUseFrameOffset { get; private set; }
82 public static float LinkConstraintEnableTransMotor { get; private set; }
83 public static float LinkConstraintTransMotorMaxVel { get; private set; }
84 public static float LinkConstraintTransMotorMaxForce { get; private set; }
85 public static float LinkConstraintERP { get; private set; }
86 public static float LinkConstraintCFM { get; private set; }
87 public static float LinkConstraintSolverIterations { get; private set; }
88
89 public static float PID_D { get; private set; } // derivative
90 public static float PID_P { get; private set; } // proportional
91
92 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
93 public delegate float ParamGet(BSScene scene);
94 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
95 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
96
97 public struct ParameterDefn
98 {
99 public string name; // string name of the parameter
100 public string desc; // a short description of what the parameter means
101 public float defaultValue; // default value if not specified anywhere else
102 public ParamUser userParam; // get the value from the configuration file
103 public ParamGet getter; // return the current value stored for this parameter
104 public ParamSet setter; // set the current value for this parameter
105 public SetOnObject onObject; // set the value on an object in the physical domain
106 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
107 {
108 name = n;
109 desc = d;
110 defaultValue = v;
111 userParam = u;
112 getter = g;
113 setter = s;
114 onObject = null;
115 }
116 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
117 {
118 name = n;
119 desc = d;
120 defaultValue = v;
121 userParam = u;
122 getter = g;
123 setter = s;
124 onObject = o;
125 }
126 }
127
128 // List of all of the externally visible parameters.
129 // For each parameter, this table maps a text name to getter and setters.
130 // To add a new externally referencable/settable parameter, add the paramter storage
131 // location somewhere in the program and make an entry in this table with the
132 // getters and setters.
133 // It is easiest to find an existing definition and copy it.
134 // Parameter values are floats. Booleans are converted to a floating value.
135 //
136 // A ParameterDefn() takes the following parameters:
137 // -- the text name of the parameter. This is used for console input and ini file.
138 // -- a short text description of the parameter. This shows up in the console listing.
139 // -- a default value (float)
140 // -- a delegate for fetching the parameter from the ini file.
141 // Should handle fetching the right type from the ini file and converting it.
142 // -- a delegate for getting the value as a float
143 // -- a delegate for setting the value from a float
144 // -- an optional delegate to update the value in the world. Most often used to
145 // push the new value to an in-world object.
146 //
147 // The single letter parameters for the delegates are:
148 // s = BSScene
149 // o = BSPhysObject
150 // p = string parameter name
151 // l = localID of referenced object
152 // v = value (float)
153 // cf = parameter configuration class (for fetching values from ini file)
154 private static ParameterDefn[] ParameterDefinitions =
155 {
156 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
157 ConfigurationParameters.numericTrue,
158 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
159 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
160 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
161 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
162 ConfigurationParameters.numericFalse,
163 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
164 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
165 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
166 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
167 ConfigurationParameters.numericTrue,
168 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
169 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
170 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
171
172 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
173 8f,
174 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
175 (s) => { return MeshLOD; },
176 (s,p,l,v) => { MeshLOD = v; } ),
177 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
178 16f,
179 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
180 (s) => { return MeshMegaPrimLOD; },
181 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
182 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
183 10f,
184 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
185 (s) => { return MeshMegaPrimThreshold; },
186 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
187 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
188 32f,
189 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
190 (s) => { return SculptLOD; },
191 (s,p,l,v) => { SculptLOD = v; } ),
192
193 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
194 10f,
195 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
196 (s) => { return (float)s.m_maxSubSteps; },
197 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
198 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
199 1f / 60f,
200 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
201 (s) => { return (float)s.m_fixedTimeStep; },
202 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
203 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
204 2048f,
205 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
206 (s) => { return (float)s.m_maxCollisionsPerFrame; },
207 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
208 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
209 8000f,
210 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
211 (s) => { return (float)s.m_maxUpdatesPerFrame; },
212 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
213 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
214 500f,
215 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
216 (s) => { return (float)s.m_taintsToProcessPerStep; },
217 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
218 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
219 0.0001f,
220 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
221 (s) => { return (float)MinimumObjectMass; },
222 (s,p,l,v) => { MinimumObjectMass = v; } ),
223 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
224 10000.01f,
225 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
226 (s) => { return (float)MaximumObjectMass; },
227 (s,p,l,v) => { MaximumObjectMass = v; } ),
228
229 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
230 2200f,
231 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
232 (s) => { return (float)PID_D; },
233 (s,p,l,v) => { PID_D = v; } ),
234 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
235 900f,
236 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
237 (s) => { return (float)PID_P; },
238 (s,p,l,v) => { PID_P = v; } ),
239
240 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
241 0.2f,
242 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
243 (s) => { return s.UnmanagedParams[0].defaultFriction; },
244 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
245 new ParameterDefn("DefaultDensity", "Density for new objects" ,
246 10.000006836f, // Aluminum g/cm3
247 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
248 (s) => { return s.UnmanagedParams[0].defaultDensity; },
249 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
250 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
251 0f,
252 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
253 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
254 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
255 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
256 0.04f,
257 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
258 (s) => { return s.UnmanagedParams[0].collisionMargin; },
259 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
260 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
261 -9.80665f,
262 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
263 (s) => { return s.UnmanagedParams[0].gravity; },
264 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
265 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
266
267
268 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
269 0f,
270 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
271 (s) => { return LinearDamping; },
272 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
273 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ),
274 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
275 0f,
276 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
277 (s) => { return AngularDamping; },
278 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
279 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ),
280 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
281 0.2f,
282 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
283 (s) => { return DeactivationTime; },
284 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
285 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
286 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
287 0.8f,
288 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
289 (s) => { return LinearSleepingThreshold; },
290 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
291 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
292 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
293 1.0f,
294 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
295 (s) => { return AngularSleepingThreshold; },
296 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
297 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
298 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
299 0f, // set to zero to disable
300 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
301 (s) => { return CcdMotionThreshold; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
303 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
304 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
305 0f,
306 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
307 (s) => { return CcdSweptSphereRadius; },
308 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
309 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
310 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
311 0.1f,
312 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
313 (s) => { return ContactProcessingThreshold; },
314 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
315 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
316
317 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
318 (float)BSTerrainPhys.TerrainImplementation.Heightmap,
319 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
320 (s) => { return TerrainImplementation; },
321 (s,p,l,v) => { TerrainImplementation = v; } ),
322 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
323 0.3f,
324 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
325 (s) => { return TerrainFriction; },
326 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
327 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
328 0.8f,
329 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
330 (s) => { return TerrainHitFraction; },
331 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
332 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
333 0f,
334 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
335 (s) => { return TerrainRestitution; },
336 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
337 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
338 0.04f,
339 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
340 (s) => { return TerrainCollisionMargin; },
341 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
342
343 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
344 0.2f,
345 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
346 (s) => { return AvatarFriction; },
347 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
348 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
349 10.0f,
350 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
351 (s) => { return AvatarStandingFriction; },
352 (s,p,l,v) => { AvatarStandingFriction = v; } ),
353 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
354 3.5f,
355 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
356 (s) => { return AvatarDensity; },
357 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
358 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
359 0f,
360 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
361 (s) => { return AvatarRestitution; },
362 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
363 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
364 0.6f,
365 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
366 (s) => { return AvatarCapsuleWidth; },
367 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
368 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
369 0.45f,
370 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
371 (s) => { return AvatarCapsuleDepth; },
372 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
373 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
374 1.5f,
375 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
376 (s) => { return AvatarCapsuleHeight; },
377 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
378 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
379 0.1f,
380 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
381 (s) => { return AvatarContactProcessingThreshold; },
382 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
383
384 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
385 0.95f,
386 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
387 (s) => { return VehicleAngularDamping; },
388 (s,p,l,v) => { VehicleAngularDamping = v; } ),
389
390 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
391 0f,
392 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
393 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
394 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
395 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
396 0f,
397 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
398 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
399 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
400 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
401 ConfigurationParameters.numericFalse,
402 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
403 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
404 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
405 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
406 ConfigurationParameters.numericFalse,
407 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
408 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
409 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
410 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
411 ConfigurationParameters.numericTrue,
412 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
413 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
414 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
415 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
416 ConfigurationParameters.numericTrue,
417 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
418 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
419 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
420 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
421 ConfigurationParameters.numericFalse,
422 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
423 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
424 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
425 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
426 0f, // zero says use Bullet default
427 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
428 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
429 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
430
431 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
432 (float)BSLinkset.LinksetImplementation.Compound,
433 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
434 (s) => { return LinksetImplementation; },
435 (s,p,l,v) => { LinksetImplementation = v; } ),
436 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
437 ConfigurationParameters.numericFalse,
438 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
439 (s) => { return LinkConstraintUseFrameOffset; },
440 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
441 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
442 ConfigurationParameters.numericTrue,
443 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
444 (s) => { return LinkConstraintEnableTransMotor; },
445 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
446 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
447 5.0f,
448 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
449 (s) => { return LinkConstraintTransMotorMaxVel; },
450 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
451 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
452 0.1f,
453 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
454 (s) => { return LinkConstraintTransMotorMaxForce; },
455 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
456 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
457 0.1f,
458 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
459 (s) => { return LinkConstraintCFM; },
460 (s,p,l,v) => { LinkConstraintCFM = v; } ),
461 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
462 0.1f,
463 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
464 (s) => { return LinkConstraintERP; },
465 (s,p,l,v) => { LinkConstraintERP = v; } ),
466 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
467 40,
468 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
469 (s) => { return LinkConstraintSolverIterations; },
470 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
471
472 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
473 0f,
474 (s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
475 (s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; },
476 (s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ),
477 };
478
479 // Convert a boolean to our numeric true and false values
480 public static float NumericBool(bool b)
481 {
482 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
483 }
484
485 // Convert numeric true and false values to a boolean
486 public static bool BoolNumeric(float b)
487 {
488 return (b == ConfigurationParameters.numericTrue ? true : false);
489 }
490
491 // Search through the parameter definitions and return the matching
492 // ParameterDefn structure.
493 // Case does not matter as names are compared after converting to lower case.
494 // Returns 'false' if the parameter is not found.
495 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
496 {
497 bool ret = false;
498 ParameterDefn foundDefn = new ParameterDefn();
499 string pName = paramName.ToLower();
500
501 foreach (ParameterDefn parm in ParameterDefinitions)
502 {
503 if (pName == parm.name.ToLower())
504 {
505 foundDefn = parm;
506 ret = true;
507 break;
508 }
509 }
510 defn = foundDefn;
511 return ret;
512 }
513
514 // Pass through the settable parameters and set the default values
515 internal static void SetParameterDefaultValues(BSScene physicsScene)
516 {
517 foreach (ParameterDefn parm in ParameterDefinitions)
518 {
519 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
520 }
521 }
522
523 // Get user set values out of the ini file.
524 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
525 {
526 foreach (ParameterDefn parm in ParameterDefinitions)
527 {
528 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
529 }
530 }
531
532 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
533
534 // This creates an array in the correct format for returning the list of
535 // parameters. This is used by the 'list' option of the 'physics' command.
536 internal static void BuildParameterTable()
537 {
538 if (SettableParameters.Length < ParameterDefinitions.Length)
539 {
540 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
541 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
542 {
543 ParameterDefn pd = ParameterDefinitions[ii];
544 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
545 }
546
547 // make the list in alphabetical order for estetic reasons
548 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
549 {
550 return ppe1.name.CompareTo(ppe2.name);
551 });
552
553 SettableParameters = entries.ToArray();
554 }
555 }
556
557
558}
559}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
new file mode 100644
index 0000000..689da7f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
@@ -0,0 +1,346 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
58public abstract class BSPhysObject : PhysicsActor
59{
60 protected BSPhysObject()
61 {
62 }
63 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
64 {
65 PhysicsScene = parentScene;
66 LocalID = localID;
67 PhysObjectName = name;
68 TypeName = typeName;
69
70 Linkset = BSLinkset.Factory(PhysicsScene, this);
71 LastAssetBuildFailed = false;
72
73 // Default material type
74 Material = MaterialAttributes.Material.Wood;
75
76 CollisionCollection = new CollisionEventUpdate();
77 SubscribedEventsMs = 0;
78 CollidingStep = 0;
79 CollidingGroundStep = 0;
80 }
81
82 // Tell the object to clean up.
83 public virtual void Destroy()
84 {
85 UnRegisterAllPreStepActions();
86 }
87
88 public BSScene PhysicsScene { get; protected set; }
89 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
90 public string PhysObjectName { get; protected set; }
91 public string TypeName { get; protected set; }
92
93 public BSLinkset Linkset { get; set; }
94 public BSLinksetInfo LinksetInfo { get; set; }
95
96 // Return the object mass without calculating it or having side effects
97 public abstract float RawMass { get; }
98 // Set the raw mass but also update physical mass properties (inertia, ...)
99 // 'inWorld' true if the object has already been added to the dynamic world.
100 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
101
102 // The last value calculated for the prim's inertia
103 public OMV.Vector3 Inertia { get; set; }
104
105 // Reference to the physical body (btCollisionObject) of this object
106 public BulletBody PhysBody;
107 // Reference to the physical shape (btCollisionShape) of this object
108 public BulletShape PhysShape;
109
110 // 'true' if the mesh's underlying asset failed to build.
111 // This will keep us from looping after the first time the build failed.
112 public bool LastAssetBuildFailed { get; set; }
113
114 // The objects base shape information. Null if not a prim type shape.
115 public PrimitiveBaseShape BaseShape { get; protected set; }
116 // Some types of objects have preferred physical representations.
117 // Returns SHAPE_UNKNOWN if there is no preference.
118 public virtual BSPhysicsShapeType PreferredPhysicalShape
119 {
120 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
121 }
122
123 // When the physical properties are updated, an EntityProperty holds the update values.
124 // Keep the current and last EntityProperties to enable computation of differences
125 // between the current update and the previous values.
126 public EntityProperties CurrentEntityProperties { get; set; }
127 public EntityProperties LastEntityProperties { get; set; }
128
129 public virtual OMV.Vector3 Scale { get; set; }
130 public abstract bool IsSolid { get; }
131 public abstract bool IsStatic { get; }
132
133 // Materialness
134 public MaterialAttributes.Material Material { get; private set; }
135 public override void SetMaterial(int material)
136 {
137 Material = (MaterialAttributes.Material)material;
138 }
139
140 // Stop all physical motion.
141 public abstract void ZeroMotion(bool inTaintTime);
142 public abstract void ZeroAngularMotion(bool inTaintTime);
143
144 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
145 public virtual void StepVehicle(float timeStep) { }
146
147 // Update the physical location and motion of the object. Called with data from Bullet.
148 public abstract void UpdateProperties(EntityProperties entprop);
149
150 public abstract OMV.Vector3 RawPosition { get; set; }
151 public abstract OMV.Vector3 ForcePosition { get; set; }
152
153 public abstract OMV.Quaternion RawOrientation { get; set; }
154 public abstract OMV.Quaternion ForceOrientation { get; set; }
155
156 // The system is telling us the velocity it wants to move at.
157 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
158 public override OMV.Vector3 TargetVelocity
159 {
160 get { return m_targetVelocity; }
161 set
162 {
163 m_targetVelocity = value;
164 Velocity = value;
165 }
166 }
167 public abstract OMV.Vector3 ForceVelocity { get; set; }
168
169 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
170
171 public abstract float ForceBuoyancy { get; set; }
172
173 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
174
175 #region Collisions
176
177 // Requested number of milliseconds between collision events. Zero means disabled.
178 protected int SubscribedEventsMs { get; set; }
179 // Given subscription, the time that a collision may be passed up
180 protected int NextCollisionOkTime { get; set; }
181 // The simulation step that last had a collision
182 protected long CollidingStep { get; set; }
183 // The simulation step that last had a collision with the ground
184 protected long CollidingGroundStep { get; set; }
185 // The collision flags we think are set in Bullet
186 protected CollisionFlags CurrentCollisionFlags { get; set; }
187
188 // The collisions that have been collected this tick
189 protected CollisionEventUpdate CollisionCollection;
190
191 // The simulation step is telling this object about a collision.
192 // Return 'true' if a collision was processed and should be sent up.
193 // Called at taint time from within the Step() function
194 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
195 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
196 {
197 bool ret = false;
198
199 // The following lines make IsColliding() and IsCollidingGround() work
200 CollidingStep = PhysicsScene.SimulationStep;
201 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
202 {
203 CollidingGroundStep = PhysicsScene.SimulationStep;
204 }
205
206 // prims in the same linkset cannot collide with each other
207 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
208 {
209 return ret;
210 }
211
212 // if someone has subscribed for collision events....
213 if (SubscribedEvents()) {
214 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
215 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
216 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
217
218 ret = true;
219 }
220 return ret;
221 }
222
223 // Send the collected collisions into the simulator.
224 // Called at taint time from within the Step() function thus no locking problems
225 // with CollisionCollection and ObjectsWithNoMoreCollisions.
226 // Return 'true' if there were some actual collisions passed up
227 public virtual bool SendCollisions()
228 {
229 bool ret = true;
230 // If the 'no collision' call, force it to happen right now so quick collision_end
231 bool force = (CollisionCollection.Count == 0);
232
233 // throttle the collisions to the number of milliseconds specified in the subscription
234 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
235 {
236 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
237
238 // We are called if we previously had collisions. If there are no collisions
239 // this time, send up one last empty event so OpenSim can sense collision end.
240 if (CollisionCollection.Count == 0)
241 {
242 // If I have no collisions this time, remove me from the list of objects with collisions.
243 ret = false;
244 }
245
246 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
247 base.SendCollisionUpdate(CollisionCollection);
248
249 // The CollisionCollection instance is passed around in the simulator.
250 // Make sure we don't have a handle to that one and that a new one is used for next time.
251 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
252 // a race condition is created for the other users of this instance.
253 CollisionCollection = new CollisionEventUpdate();
254 }
255 return ret;
256 }
257
258 // Subscribe for collision events.
259 // Parameter is the millisecond rate the caller wishes collision events to occur.
260 public override void SubscribeEvents(int ms) {
261 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
262 SubscribedEventsMs = ms;
263 if (ms > 0)
264 {
265 // make sure first collision happens
266 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
267
268 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
269 {
270 if (PhysBody.HasPhysicalBody)
271 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
272 });
273 }
274 else
275 {
276 // Subscribing for zero or less is the same as unsubscribing
277 UnSubscribeEvents();
278 }
279 }
280 public override void UnSubscribeEvents() {
281 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
282 SubscribedEventsMs = 0;
283 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
284 {
285 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
286 if (PhysBody.HasPhysicalBody)
287 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
288 });
289 }
290 // Return 'true' if the simulator wants collision events
291 public override bool SubscribedEvents() {
292 return (SubscribedEventsMs > 0);
293 }
294
295 #endregion // Collisions
296
297 #region Per Simulation Step actions
298 // There are some actions that must be performed for a physical object before each simulation step.
299 // These actions are optional so, rather than scanning all the physical objects and asking them
300 // if they have anything to do, a physical object registers for an event call before the step is performed.
301 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
302 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
303 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
304 {
305 string identifier = op + "-" + id.ToString();
306 RegisteredActions[identifier] = actn;
307 PhysicsScene.BeforeStep += actn;
308 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
309 }
310
311 // Unregister a pre step action. Safe to call if the action has not been registered.
312 protected void UnRegisterPreStepAction(string op, uint id)
313 {
314 string identifier = op + "-" + id.ToString();
315 bool removed = false;
316 if (RegisteredActions.ContainsKey(identifier))
317 {
318 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
319 RegisteredActions.Remove(identifier);
320 removed = true;
321 }
322 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
323 }
324
325 protected void UnRegisterAllPreStepActions()
326 {
327 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
328 {
329 PhysicsScene.BeforeStep -= kvp.Value;
330 }
331 RegisteredActions.Clear();
332 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
333 }
334
335
336 #endregion // Per Simulation Step actions
337
338 // High performance detailed logging routine used by the physical objects.
339 protected void DetailLog(string msg, params Object[] args)
340 {
341 if (PhysicsScene.PhysicsLogging.Enabled)
342 PhysicsScene.DetailLog(msg, args);
343 }
344
345}
346}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs
new file mode 100644
index 0000000..75963ee
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs
@@ -0,0 +1,81 @@
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 OpenSim.Framework;
30using OpenSim.Region.Physics.Manager;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
40 /// The unmanaged library is compiled and linked statically with Bullet
41 /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
42 /// </summary>
43public class BSPlugin : IPhysicsPlugin
44{
45 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 private BSScene _mScene;
48
49 public BSPlugin()
50 {
51 }
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (_mScene == null)
61 {
62
63 // If not Windows, loading is performed by the
64 // Mono loader as specified in
65 // "bin/Physics/OpenSim.Region.Physics.BulletSNPlugin.dll.config".
66
67 _mScene = new BSScene(sceneIdentifier);
68 }
69 return (_mScene);
70 }
71
72 public string GetName()
73 {
74 return ("BulletSimN");
75 }
76
77 public void Dispose()
78 {
79 }
80}
81}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
new file mode 100644
index 0000000..aadb5b2
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
@@ -0,0 +1,1494 @@
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 */
27
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenSim.Region.Physics.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.Physics.BulletSNPlugin
39{
40
41 [Serializable]
42public sealed class BSPrim : BSPhysObject
43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]";
46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
49
50 private bool _grabbed;
51 private bool _isSelected;
52 private bool _isVolumeDetect;
53 private OMV.Vector3 _position;
54 private float _mass; // the mass of this object
55 private float _density;
56 private OMV.Vector3 _force;
57 private OMV.Vector3 _velocity;
58 private OMV.Vector3 _torque;
59 private float _collisionScore;
60 private OMV.Vector3 _acceleration;
61 private OMV.Quaternion _orientation;
62 private int _physicsActorType;
63 private bool _isPhysical;
64 private bool _flying;
65 private float _friction;
66 private float _restitution;
67 private bool _setAlwaysRun;
68 private bool _throttleUpdates;
69 private bool _isColliding;
70 private bool _collidingGround;
71 private bool _collidingObj;
72 private bool _floatOnWater;
73 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic;
75 private float _buoyancy;
76
77 private BSDynamics _vehicle;
78
79 private OMV.Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
89 : base(parent_scene, localID, primName, "BSPrim")
90 {
91 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
92 _physicsActorType = (int)ActorTypes.Prim;
93 _position = pos;
94 _size = size;
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation;
97 _buoyancy = 1f;
98 _velocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs;
101 _isPhysical = pisPhysical;
102 _isVolumeDetect = false;
103
104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
106 _density = PhysicsScene.Params.defaultDensity;
107 _friction = PhysicsScene.Params.defaultFriction;
108 _restitution = PhysicsScene.Params.defaultRestitution;
109
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
111
112 _mass = CalculateMass();
113
114 Linkset.Refresh(this);
115
116 DetailLog("{0},BSPrim.constructor,call", LocalID);
117 // do the actual object creation at taint time
118 PhysicsScene.TaintedObject("BSPrim.create", delegate()
119 {
120 CreateGeomAndObject(true);
121
122 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
123 });
124 }
125
126 // called when this prim is being destroyed and we should free all the resources
127 public override void Destroy()
128 {
129 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
130 base.Destroy();
131
132 // Undo any links between me and any other object
133 BSPhysObject parentBefore = Linkset.LinksetRoot;
134 int childrenBefore = Linkset.NumberOfChildren;
135
136 Linkset = Linkset.RemoveMeFromLinkset(this);
137
138 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
139 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
140
141 // Undo any vehicle properties
142 this.VehicleType = (int)Vehicle.TYPE_NONE;
143
144 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
145 {
146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
147 // If there are physical body and shape, release my use of same.
148 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
149 PhysBody.Clear();
150 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
151 PhysShape.Clear();
152 });
153 }
154
155 // No one uses this property.
156 public override bool Stopped {
157 get { return false; }
158 }
159 public override OMV.Vector3 Size {
160 get { return _size; }
161 set {
162 // We presume the scale and size are the same. If scale must be changed for
163 // the physical shape, that is done when the geometry is built.
164 _size = value;
165 Scale = _size;
166 ForceBodyShapeRebuild(false);
167 }
168 }
169
170 public override PrimitiveBaseShape Shape {
171 set {
172 BaseShape = value;
173 ForceBodyShapeRebuild(false);
174 }
175 }
176 // Whatever the linkset wants is what I want.
177 public override BSPhysicsShapeType PreferredPhysicalShape
178 { get { return Linkset.PreferredPhysicalShape(this); } }
179
180 public override bool ForceBodyShapeRebuild(bool inTaintTime)
181 {
182 LastAssetBuildFailed = false;
183 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
184 {
185 _mass = CalculateMass(); // changing the shape changes the mass
186 CreateGeomAndObject(true);
187 });
188 return true;
189 }
190 public override bool Grabbed {
191 set { _grabbed = value;
192 }
193 }
194 public override bool Selected {
195 set
196 {
197 if (value != _isSelected)
198 {
199 _isSelected = value;
200 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
201 {
202 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
203 SetObjectDynamic(false);
204 });
205 }
206 }
207 }
208 public override void CrossingFailure() { return; }
209
210 // link me to the specified parent
211 public override void link(PhysicsActor obj) {
212 BSPrim parent = obj as BSPrim;
213 if (parent != null)
214 {
215 BSPhysObject parentBefore = Linkset.LinksetRoot;
216 int childrenBefore = Linkset.NumberOfChildren;
217
218 Linkset = parent.Linkset.AddMeToLinkset(this);
219
220 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
221 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
222 }
223 return;
224 }
225
226 // delink me from my linkset
227 public override void delink() {
228 // TODO: decide if this parent checking needs to happen at taint time
229 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
230
231 BSPhysObject parentBefore = Linkset.LinksetRoot;
232 int childrenBefore = Linkset.NumberOfChildren;
233
234 Linkset = Linkset.RemoveMeFromLinkset(this);
235
236 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
237 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
238 return;
239 }
240
241 // Set motion values to zero.
242 // Do it to the properties so the values get set in the physics engine.
243 // Push the setting of the values to the viewer.
244 // Called at taint time!
245 public override void ZeroMotion(bool inTaintTime)
246 {
247 _velocity = OMV.Vector3.Zero;
248 _acceleration = OMV.Vector3.Zero;
249 _rotationalVelocity = OMV.Vector3.Zero;
250
251 // Zero some other properties in the physics engine
252 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
253 {
254 if (PhysBody.HasPhysicalBody)
255 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
256 });
257 }
258 public override void ZeroAngularMotion(bool inTaintTime)
259 {
260 _rotationalVelocity = OMV.Vector3.Zero;
261 // Zero some other properties in the physics engine
262 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
263 {
264 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
265 if (PhysBody.HasPhysicalBody)
266 {
267 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
268 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
269 }
270 });
271 }
272
273 public override void LockAngularMotion(OMV.Vector3 axis)
274 {
275 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
276 return;
277 }
278
279 public override OMV.Vector3 RawPosition
280 {
281 get { return _position; }
282 set { _position = value; }
283 }
284 public override OMV.Vector3 Position {
285 get {
286 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
287 * and does not fetch this position info for children. Thus this is commented out.
288 // child prims move around based on their parent. Need to get the latest location
289 if (!Linkset.IsRoot(this))
290 _position = Linkset.PositionGet(this);
291 */
292
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
294 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position;
296 }
297 set {
298 // If the position must be forced into the physics engine, use ForcePosition.
299 // All positions are given in world positions.
300 if (_position == value)
301 {
302 DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
303 return;
304 }
305 _position = value;
306 PositionSanityCheck(false);
307
308 // A linkset might need to know if a component information changed.
309 Linkset.UpdateProperties(this, false);
310
311 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
312 {
313 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
314 ForcePosition = _position;
315 });
316 }
317 }
318 public override OMV.Vector3 ForcePosition {
319 get {
320 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
321 return _position;
322 }
323 set {
324 _position = value;
325 if (PhysBody.HasPhysicalBody)
326 {
327 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
328 ActivateIfPhysical(false);
329 }
330 }
331 }
332
333 // Check that the current position is sane and, if not, modify the position to make it so.
334 // Check for being below terrain and being out of bounds.
335 // Returns 'true' of the position was made sane by some action.
336 private bool PositionSanityCheck(bool inTaintTime)
337 {
338 bool ret = false;
339
340 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
341 {
342 // The physical object is out of the known/simulated area.
343 // Upper levels of code will handle the transition to other areas so, for
344 // the time, we just ignore the position.
345 return ret;
346 }
347
348 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
349 OMV.Vector3 upForce = OMV.Vector3.Zero;
350 if (RawPosition.Z < terrainHeight)
351 {
352 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
353 float targetHeight = terrainHeight + (Size.Z / 2f);
354 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
355 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
356 ret = true;
357 }
358
359 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
360 {
361 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
362 // TODO: a floating motor so object will bob in the water
363 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
364 {
365 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
366 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
367 ret = true;
368 }
369 }
370
371 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
372 // TODO: This should be intergrated with a geneal physics action mechanism.
373 // TODO: This should be moderated with PID'ness.
374 if (ret)
375 {
376 // Apply upforce and overcome gravity.
377 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
378 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
379 AddForce(correctionForce, false, inTaintTime);
380 }
381 return ret;
382 }
383
384 // Return the effective mass of the object.
385 // The definition of this call is to return the mass of the prim.
386 // If the simulator cares about the mass of the linkset, it will sum it itself.
387 public override float Mass
388 {
389 get
390 {
391 return _mass;
392 }
393 }
394
395 // used when we only want this prim's mass and not the linkset thing
396 public override float RawMass {
397 get { return _mass; }
398 }
399 // Set the physical mass to the passed mass.
400 // Note that this does not change _mass!
401 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
402 {
403 if (PhysBody.HasPhysicalBody)
404 {
405 if (IsStatic)
406 {
407 Inertia = OMV.Vector3.Zero;
408 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
409 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
410 }
411 else
412 {
413 if (inWorld)
414 {
415 // Changing interesting properties doesn't change proxy and collision cache
416 // information. The Bullet solution is to re-add the object to the world
417 // after parameters are changed.
418 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
419 }
420
421 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
422 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
423 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
424
425 // center of mass is at the zero of the object
426 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
427 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},inWorld={3}", LocalID, physMass, Inertia, inWorld);
428
429 if (inWorld)
430 {
431 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr,_position,_orientation);
432 }
433
434 // Must set gravity after it has been added to the world because, for unknown reasons,
435 // adding the object resets the object's gravity to world gravity
436 OMV.Vector3 grav = PhysicsScene.DefaultGravity * (1f - Buoyancy);
437 BulletSimAPI.SetGravity2(PhysBody.ptr, grav);
438
439 }
440 }
441 }
442
443 // Is this used?
444 public override OMV.Vector3 CenterOfMass
445 {
446 get { return Linkset.CenterOfMass; }
447 }
448
449 // Is this used?
450 public override OMV.Vector3 GeometricCenter
451 {
452 get { return Linkset.GeometricCenter; }
453 }
454
455 public override OMV.Vector3 Force {
456 get { return _force; }
457 set {
458 _force = value;
459 if (_force != OMV.Vector3.Zero)
460 {
461 // If the force is non-zero, it must be reapplied each tick because
462 // Bullet clears the forces applied last frame.
463 RegisterPreStepAction("BSPrim.setForce", LocalID,
464 delegate(float timeStep)
465 {
466 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
467 if (PhysBody.HasPhysicalBody)
468 {
469 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force);
470 ActivateIfPhysical(false);
471 }
472 }
473 );
474 }
475 else
476 {
477 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
478 }
479 }
480 }
481
482 public override int VehicleType {
483 get {
484 return (int)_vehicle.Type; // if we are a vehicle, return that type
485 }
486 set {
487 Vehicle type = (Vehicle)value;
488
489 PhysicsScene.TaintedObject("setVehicleType", delegate()
490 {
491 // Done at taint time so we're sure the physics engine is not using the variables
492 // Vehicle code changes the parameters for this vehicle type.
493 _vehicle.ProcessTypeChange(type);
494 ActivateIfPhysical(false);
495
496 // If an active vehicle, register the vehicle code to be called before each step
497 if (_vehicle.Type == Vehicle.TYPE_NONE)
498 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
499 else
500 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
501 });
502 }
503 }
504 public override void VehicleFloatParam(int param, float value)
505 {
506 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
507 {
508 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
509 ActivateIfPhysical(false);
510 });
511 }
512 public override void VehicleVectorParam(int param, OMV.Vector3 value)
513 {
514 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
515 {
516 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
517 ActivateIfPhysical(false);
518 });
519 }
520 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
521 {
522 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
523 {
524 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
525 ActivateIfPhysical(false);
526 });
527 }
528 public override void VehicleFlags(int param, bool remove)
529 {
530 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
531 {
532 _vehicle.ProcessVehicleFlags(param, remove);
533 });
534 }
535
536 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
537 public override void SetVolumeDetect(int param) {
538 bool newValue = (param != 0);
539 if (_isVolumeDetect != newValue)
540 {
541 _isVolumeDetect = newValue;
542 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
543 {
544 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
545 SetObjectDynamic(true);
546 });
547 }
548 return;
549 }
550 public override OMV.Vector3 Velocity {
551 get { return _velocity; }
552 set {
553 _velocity = value;
554 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
555 {
556 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
557 ForceVelocity = _velocity;
558 });
559 }
560 }
561 public override OMV.Vector3 ForceVelocity {
562 get { return _velocity; }
563 set {
564 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
565
566 _velocity = value;
567 if (PhysBody.HasPhysicalBody)
568 {
569 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
570 ActivateIfPhysical(false);
571 }
572 }
573 }
574 public override OMV.Vector3 Torque {
575 get { return _torque; }
576 set {
577 _torque = value;
578 if (_torque != OMV.Vector3.Zero)
579 {
580 // If the torque is non-zero, it must be reapplied each tick because
581 // Bullet clears the forces applied last frame.
582 RegisterPreStepAction("BSPrim.setTorque", LocalID,
583 delegate(float timeStep)
584 {
585 if (PhysBody.HasPhysicalBody)
586 AddAngularForce(_torque, false, true);
587 }
588 );
589 }
590 else
591 {
592 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
593 }
594 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
595 }
596 }
597 public override float CollisionScore {
598 get { return _collisionScore; }
599 set { _collisionScore = value;
600 }
601 }
602 public override OMV.Vector3 Acceleration {
603 get { return _acceleration; }
604 set { _acceleration = value; }
605 }
606 public override OMV.Quaternion RawOrientation
607 {
608 get { return _orientation; }
609 set { _orientation = value; }
610 }
611 public override OMV.Quaternion Orientation {
612 get {
613 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
614 * and does not fetch this position info for children. Thus this is commented out.
615 // Children move around because tied to parent. Get a fresh value.
616 if (!Linkset.IsRoot(this))
617 {
618 _orientation = Linkset.OrientationGet(this);
619 }
620 */
621 return _orientation;
622 }
623 set {
624 if (_orientation == value)
625 return;
626 _orientation = value;
627
628 // A linkset might need to know if a component information changed.
629 Linkset.UpdateProperties(this, false);
630
631 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
632 {
633 if (PhysBody.HasPhysicalBody)
634 {
635 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
636 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
637 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
638 }
639 });
640 }
641 }
642 // Go directly to Bullet to get/set the value.
643 public override OMV.Quaternion ForceOrientation
644 {
645 get
646 {
647 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
648 return _orientation;
649 }
650 set
651 {
652 _orientation = value;
653 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
654 }
655 }
656 public override int PhysicsActorType {
657 get { return _physicsActorType; }
658 set { _physicsActorType = value; }
659 }
660 public override bool IsPhysical {
661 get { return _isPhysical; }
662 set {
663 if (_isPhysical != value)
664 {
665 _isPhysical = value;
666 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
667 {
668 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
669 SetObjectDynamic(true);
670 // whether phys-to-static or static-to-phys, the object is not moving.
671 ZeroMotion(true);
672 });
673 }
674 }
675 }
676
677 // An object is static (does not move) if selected or not physical
678 public override bool IsStatic
679 {
680 get { return _isSelected || !IsPhysical; }
681 }
682
683 // An object is solid if it's not phantom and if it's not doing VolumeDetect
684 public override bool IsSolid
685 {
686 get { return !IsPhantom && !_isVolumeDetect; }
687 }
688
689 // Make gravity work if the object is physical and not selected
690 // Called at taint-time!!
691 private void SetObjectDynamic(bool forceRebuild)
692 {
693 // Recreate the physical object if necessary
694 CreateGeomAndObject(forceRebuild);
695 }
696
697 // Convert the simulator's physical properties into settings on BulletSim objects.
698 // There are four flags we're interested in:
699 // IsStatic: Object does not move, otherwise the object has mass and moves
700 // isSolid: other objects bounce off of this object
701 // isVolumeDetect: other objects pass through but can generate collisions
702 // collisionEvents: whether this object returns collision events
703 private void UpdatePhysicalParameters()
704 {
705 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
706
707 // Mangling all the physical properties requires the object not be in the physical world.
708 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
709 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
710
711 // Set up the object physicalness (does gravity and collisions move this object)
712 MakeDynamic(IsStatic);
713
714 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
715 _vehicle.Refresh();
716
717 // Arrange for collision events if the simulator wants them
718 EnableCollisions(SubscribedEvents());
719
720 // Make solid or not (do things bounce off or pass through this object).
721 MakeSolid(IsSolid);
722
723 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
724
725 // Rebuild its shape
726 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
727
728 // Collision filter can be set only when the object is in the world
729 PhysBody.ApplyCollisionMask();
730
731 // Recompute any linkset parameters.
732 // When going from non-physical to physical, this re-enables the constraints that
733 // had been automatically disabled when the mass was set to zero.
734 // For compound based linksets, this enables and disables interactions of the children.
735 Linkset.Refresh(this);
736
737 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
738 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
739 }
740
741 // "Making dynamic" means changing to and from static.
742 // When static, gravity does not effect the object and it is fixed in space.
743 // When dynamic, the object can fall and be pushed by others.
744 // This is independent of its 'solidness' which controls what passes through
745 // this object and what interacts with it.
746 private void MakeDynamic(bool makeStatic)
747 {
748 if (makeStatic)
749 {
750 // Become a Bullet 'static' object type
751 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
752 // Stop all movement
753 ZeroMotion(true);
754
755 // Set various physical properties so other object interact properly
756 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
757 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
758 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
759
760 // Mass is zero which disables a bunch of physics stuff in Bullet
761 UpdatePhysicalMassProperties(0f, false);
762 // Set collision detection parameters
763 if (BSParam.CcdMotionThreshold > 0f)
764 {
765 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
766 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
767 }
768
769 // The activation state is 'disabled' so Bullet will not try to act on it.
770 // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
771 // Start it out sleeping and physical actions could wake it up.
772 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
773
774 // This collides like a static object
775 PhysBody.collisionType = CollisionType.Static;
776
777 // There can be special things needed for implementing linksets
778 Linkset.MakeStatic(this);
779 }
780 else
781 {
782 // Not a Bullet static object
783 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
784
785 // Set various physical properties so other object interact properly
786 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
787 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
788 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
789
790 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
791 // Since this can be called multiple times, only zero forces when becoming physical
792 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
793
794 // For good measure, make sure the transform is set through to the motion state
795 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
796
797 // Center of mass is at the center of the object
798 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
799
800 // A dynamic object has mass
801 UpdatePhysicalMassProperties(RawMass, false);
802
803 // Set collision detection parameters
804 if (BSParam.CcdMotionThreshold > 0f)
805 {
806 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
807 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
808 }
809
810 // Various values for simulation limits
811 BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping);
812 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime);
813 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
814 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
815
816 // This collides like an object.
817 PhysBody.collisionType = CollisionType.Dynamic;
818
819 // Force activation of the object so Bullet will act on it.
820 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
821 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
822
823 // There might be special things needed for implementing linksets.
824 Linkset.MakeDynamic(this);
825 }
826 }
827
828 // "Making solid" means that other object will not pass through this object.
829 // To make transparent, we create a Bullet ghost object.
830 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
831 // the functions after this one set up the state of a possibly newly created collision body.
832 private void MakeSolid(bool makeSolid)
833 {
834 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
835 if (makeSolid)
836 {
837 // Verify the previous code created the correct shape for this type of thing.
838 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
839 {
840 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
841 }
842 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
843 }
844 else
845 {
846 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
847 {
848 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
849 }
850 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
851
852 // Change collision info from a static object to a ghosty collision object
853 PhysBody.collisionType = CollisionType.VolumeDetect;
854 }
855 }
856
857 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
858 // they need waking up when parameters are changed.
859 // Called in taint-time!!
860 private void ActivateIfPhysical(bool forceIt)
861 {
862 if (IsPhysical && PhysBody.HasPhysicalBody)
863 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
864 }
865
866 // Turn on or off the flag controlling whether collision events are returned to the simulator.
867 private void EnableCollisions(bool wantsCollisionEvents)
868 {
869 if (wantsCollisionEvents)
870 {
871 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
872 }
873 else
874 {
875 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
876 }
877 }
878
879 // prims don't fly
880 public override bool Flying {
881 get { return _flying; }
882 set {
883 _flying = value;
884 }
885 }
886 public override bool SetAlwaysRun {
887 get { return _setAlwaysRun; }
888 set { _setAlwaysRun = value; }
889 }
890 public override bool ThrottleUpdates {
891 get { return _throttleUpdates; }
892 set { _throttleUpdates = value; }
893 }
894 public override bool IsColliding {
895 get { return (CollidingStep == PhysicsScene.SimulationStep); }
896 set { _isColliding = value; }
897 }
898 public override bool CollidingGround {
899 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
900 set { _collidingGround = value; }
901 }
902 public override bool CollidingObj {
903 get { return _collidingObj; }
904 set { _collidingObj = value; }
905 }
906 public bool IsPhantom {
907 get {
908 // SceneObjectPart removes phantom objects from the physics scene
909 // so, although we could implement touching and such, we never
910 // are invoked as a phantom object
911 return false;
912 }
913 }
914 public override bool FloatOnWater {
915 set {
916 _floatOnWater = value;
917 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
918 {
919 if (_floatOnWater)
920 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
921 else
922 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
923 });
924 }
925 }
926 public override OMV.Vector3 RotationalVelocity {
927 get {
928 return _rotationalVelocity;
929 }
930 set {
931 _rotationalVelocity = value;
932 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
933 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
934 {
935 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
936 ForceRotationalVelocity = _rotationalVelocity;
937 });
938 }
939 }
940 public override OMV.Vector3 ForceRotationalVelocity {
941 get {
942 return _rotationalVelocity;
943 }
944 set {
945 _rotationalVelocity = value;
946 if (PhysBody.HasPhysicalBody)
947 {
948 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
949 ActivateIfPhysical(false);
950 }
951 }
952 }
953 public override bool Kinematic {
954 get { return _kinematic; }
955 set { _kinematic = value;
956 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
957 }
958 }
959 public override float Buoyancy {
960 get { return _buoyancy; }
961 set {
962 _buoyancy = value;
963 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
964 {
965 ForceBuoyancy = _buoyancy;
966 });
967 }
968 }
969 public override float ForceBuoyancy {
970 get { return _buoyancy; }
971 set {
972 _buoyancy = value;
973 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
974 // Force the recalculation of the various inertia,etc variables in the object
975 UpdatePhysicalMassProperties(_mass, true);
976 ActivateIfPhysical(false);
977 }
978 }
979
980 // Used for MoveTo
981 public override OMV.Vector3 PIDTarget {
982 set { _PIDTarget = value; }
983 }
984 public override bool PIDActive {
985 set { _usePID = value; }
986 }
987 public override float PIDTau {
988 set { _PIDTau = value; }
989 }
990
991 // Used for llSetHoverHeight and maybe vehicle height
992 // Hover Height will override MoveTo target's Z
993 public override bool PIDHoverActive {
994 set { _useHoverPID = value; }
995 }
996 public override float PIDHoverHeight {
997 set { _PIDHoverHeight = value; }
998 }
999 public override PIDHoverType PIDHoverType {
1000 set { _PIDHoverType = value; }
1001 }
1002 public override float PIDHoverTau {
1003 set { _PIDHoverTao = value; }
1004 }
1005
1006 // For RotLookAt
1007 public override OMV.Quaternion APIDTarget { set { return; } }
1008 public override bool APIDActive { set { return; } }
1009 public override float APIDStrength { set { return; } }
1010 public override float APIDDamping { set { return; } }
1011
1012 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1013 // Since this force is being applied in only one step, make this a force per second.
1014 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1015 AddForce(addForce, pushforce, false);
1016 }
1017 // Applying a force just adds this to the total force on the object.
1018 // This added force will only last the next simulation tick.
1019 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1020 // for an object, doesn't matter if force is a pushforce or not
1021 if (force.IsFinite())
1022 {
1023 float magnitude = force.Length();
1024 if (magnitude > 20000f)
1025 {
1026 // Force has a limit
1027 force = force / magnitude * 20000f;
1028 }
1029
1030 OMV.Vector3 addForce = force;
1031 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1032
1033 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1034 {
1035 // Bullet adds this central force to the total force for this tick
1036 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1037 if (PhysBody.HasPhysicalBody)
1038 {
1039 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce);
1040 ActivateIfPhysical(false);
1041 }
1042 });
1043 }
1044 else
1045 {
1046 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1047 return;
1048 }
1049 }
1050
1051 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
1052 AddAngularForce(force, pushforce, false);
1053 }
1054 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1055 {
1056 if (force.IsFinite())
1057 {
1058 OMV.Vector3 angForce = force;
1059 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1060 {
1061 if (PhysBody.HasPhysicalBody)
1062 {
1063 BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce);
1064 ActivateIfPhysical(false);
1065 }
1066 });
1067 }
1068 else
1069 {
1070 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1071 return;
1072 }
1073 }
1074
1075 // A torque impulse.
1076 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1077 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1078 // Computed as: angularVelocity += impulse * inertia;
1079 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1080 {
1081 OMV.Vector3 applyImpulse = impulse;
1082 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1083 {
1084 if (PhysBody.HasPhysicalBody)
1085 {
1086 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1087 ActivateIfPhysical(false);
1088 }
1089 });
1090 }
1091
1092 public override void SetMomentum(OMV.Vector3 momentum) {
1093 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1094 }
1095 #region Mass Calculation
1096
1097 private float CalculateMass()
1098 {
1099 float volume = _size.X * _size.Y * _size.Z; // default
1100 float tmp;
1101
1102 float returnMass = 0;
1103 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1104 float hollowVolume = hollowAmount * hollowAmount;
1105
1106 switch (BaseShape.ProfileShape)
1107 {
1108 case ProfileShape.Square:
1109 // default box
1110
1111 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1112 {
1113 if (hollowAmount > 0.0)
1114 {
1115 switch (BaseShape.HollowShape)
1116 {
1117 case HollowShape.Square:
1118 case HollowShape.Same:
1119 break;
1120
1121 case HollowShape.Circle:
1122
1123 hollowVolume *= 0.78539816339f;
1124 break;
1125
1126 case HollowShape.Triangle:
1127
1128 hollowVolume *= (0.5f * .5f);
1129 break;
1130
1131 default:
1132 hollowVolume = 0;
1133 break;
1134 }
1135 volume *= (1.0f - hollowVolume);
1136 }
1137 }
1138
1139 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1140 {
1141 //a tube
1142
1143 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1144 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1145 volume -= volume*tmp*tmp;
1146
1147 if (hollowAmount > 0.0)
1148 {
1149 hollowVolume *= hollowAmount;
1150
1151 switch (BaseShape.HollowShape)
1152 {
1153 case HollowShape.Square:
1154 case HollowShape.Same:
1155 break;
1156
1157 case HollowShape.Circle:
1158 hollowVolume *= 0.78539816339f;;
1159 break;
1160
1161 case HollowShape.Triangle:
1162 hollowVolume *= 0.5f * 0.5f;
1163 break;
1164 default:
1165 hollowVolume = 0;
1166 break;
1167 }
1168 volume *= (1.0f - hollowVolume);
1169 }
1170 }
1171
1172 break;
1173
1174 case ProfileShape.Circle:
1175
1176 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1177 {
1178 volume *= 0.78539816339f; // elipse base
1179
1180 if (hollowAmount > 0.0)
1181 {
1182 switch (BaseShape.HollowShape)
1183 {
1184 case HollowShape.Same:
1185 case HollowShape.Circle:
1186 break;
1187
1188 case HollowShape.Square:
1189 hollowVolume *= 0.5f * 2.5984480504799f;
1190 break;
1191
1192 case HollowShape.Triangle:
1193 hollowVolume *= .5f * 1.27323954473516f;
1194 break;
1195
1196 default:
1197 hollowVolume = 0;
1198 break;
1199 }
1200 volume *= (1.0f - hollowVolume);
1201 }
1202 }
1203
1204 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1205 {
1206 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1207 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1208 volume *= (1.0f - tmp * tmp);
1209
1210 if (hollowAmount > 0.0)
1211 {
1212
1213 // calculate the hollow volume by it's shape compared to the prim shape
1214 hollowVolume *= hollowAmount;
1215
1216 switch (BaseShape.HollowShape)
1217 {
1218 case HollowShape.Same:
1219 case HollowShape.Circle:
1220 break;
1221
1222 case HollowShape.Square:
1223 hollowVolume *= 0.5f * 2.5984480504799f;
1224 break;
1225
1226 case HollowShape.Triangle:
1227 hollowVolume *= .5f * 1.27323954473516f;
1228 break;
1229
1230 default:
1231 hollowVolume = 0;
1232 break;
1233 }
1234 volume *= (1.0f - hollowVolume);
1235 }
1236 }
1237 break;
1238
1239 case ProfileShape.HalfCircle:
1240 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1241 {
1242 volume *= 0.52359877559829887307710723054658f;
1243 }
1244 break;
1245
1246 case ProfileShape.EquilateralTriangle:
1247
1248 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1249 {
1250 volume *= 0.32475953f;
1251
1252 if (hollowAmount > 0.0)
1253 {
1254
1255 // calculate the hollow volume by it's shape compared to the prim shape
1256 switch (BaseShape.HollowShape)
1257 {
1258 case HollowShape.Same:
1259 case HollowShape.Triangle:
1260 hollowVolume *= .25f;
1261 break;
1262
1263 case HollowShape.Square:
1264 hollowVolume *= 0.499849f * 3.07920140172638f;
1265 break;
1266
1267 case HollowShape.Circle:
1268 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1269 // Cyllinder hollow volume calculation
1270
1271 hollowVolume *= 0.1963495f * 3.07920140172638f;
1272 break;
1273
1274 default:
1275 hollowVolume = 0;
1276 break;
1277 }
1278 volume *= (1.0f - hollowVolume);
1279 }
1280 }
1281 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1282 {
1283 volume *= 0.32475953f;
1284 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1285 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1286 volume *= (1.0f - tmp * tmp);
1287
1288 if (hollowAmount > 0.0)
1289 {
1290
1291 hollowVolume *= hollowAmount;
1292
1293 switch (BaseShape.HollowShape)
1294 {
1295 case HollowShape.Same:
1296 case HollowShape.Triangle:
1297 hollowVolume *= .25f;
1298 break;
1299
1300 case HollowShape.Square:
1301 hollowVolume *= 0.499849f * 3.07920140172638f;
1302 break;
1303
1304 case HollowShape.Circle:
1305
1306 hollowVolume *= 0.1963495f * 3.07920140172638f;
1307 break;
1308
1309 default:
1310 hollowVolume = 0;
1311 break;
1312 }
1313 volume *= (1.0f - hollowVolume);
1314 }
1315 }
1316 break;
1317
1318 default:
1319 break;
1320 }
1321
1322
1323
1324 float taperX1;
1325 float taperY1;
1326 float taperX;
1327 float taperY;
1328 float pathBegin;
1329 float pathEnd;
1330 float profileBegin;
1331 float profileEnd;
1332
1333 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1334 {
1335 taperX1 = BaseShape.PathScaleX * 0.01f;
1336 if (taperX1 > 1.0f)
1337 taperX1 = 2.0f - taperX1;
1338 taperX = 1.0f - taperX1;
1339
1340 taperY1 = BaseShape.PathScaleY * 0.01f;
1341 if (taperY1 > 1.0f)
1342 taperY1 = 2.0f - taperY1;
1343 taperY = 1.0f - taperY1;
1344 }
1345 else
1346 {
1347 taperX = BaseShape.PathTaperX * 0.01f;
1348 if (taperX < 0.0f)
1349 taperX = -taperX;
1350 taperX1 = 1.0f - taperX;
1351
1352 taperY = BaseShape.PathTaperY * 0.01f;
1353 if (taperY < 0.0f)
1354 taperY = -taperY;
1355 taperY1 = 1.0f - taperY;
1356
1357 }
1358
1359
1360 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1361
1362 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1363 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1364 volume *= (pathEnd - pathBegin);
1365
1366 // this is crude aproximation
1367 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1368 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1369 volume *= (profileEnd - profileBegin);
1370
1371 returnMass = _density * volume;
1372
1373 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1374 if (IsRootOfLinkset)
1375 {
1376 foreach (BSPrim prim in _childrenPrims)
1377 {
1378 returnMass += prim.CalculateMass();
1379 }
1380 }
1381 */
1382
1383 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1384
1385 return returnMass;
1386 }// end CalculateMass
1387 #endregion Mass Calculation
1388
1389 // Rebuild the geometry and object.
1390 // This is called when the shape changes so we need to recreate the mesh/hull.
1391 // Called at taint-time!!!
1392 public void CreateGeomAndObject(bool forceRebuild)
1393 {
1394 // If this prim is part of a linkset, we must remove and restore the physical
1395 // links if the body is rebuilt.
1396 bool needToRestoreLinkset = false;
1397 bool needToRestoreVehicle = false;
1398
1399 // Create the correct physical representation for this type of object.
1400 // Updates PhysBody and PhysShape with the new information.
1401 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1402 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1403 {
1404 // Called if the current prim body is about to be destroyed.
1405 // Remove all the physical dependencies on the old body.
1406 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1407 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1408 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1409 });
1410
1411 if (needToRestoreLinkset)
1412 {
1413 // If physical body dependencies were removed, restore them
1414 Linkset.RestoreBodyDependencies(this);
1415 }
1416 if (needToRestoreVehicle)
1417 {
1418 // If physical body dependencies were removed, restore them
1419 _vehicle.RestoreBodyDependencies(this);
1420 }
1421
1422 // Make sure the properties are set on the new object
1423 UpdatePhysicalParameters();
1424 return;
1425 }
1426
1427 // The physics engine says that properties have updated. Update same and inform
1428 // the world that things have changed.
1429 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1430 enum UpdatedProperties {
1431 Position = 1 << 0,
1432 Rotation = 1 << 1,
1433 Velocity = 1 << 2,
1434 Acceleration = 1 << 3,
1435 RotationalVel = 1 << 4
1436 }
1437
1438 const float ROTATION_TOLERANCE = 0.01f;
1439 const float VELOCITY_TOLERANCE = 0.001f;
1440 const float POSITION_TOLERANCE = 0.05f;
1441 const float ACCELERATION_TOLERANCE = 0.01f;
1442 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1443
1444 public override void UpdateProperties(EntityProperties entprop)
1445 {
1446 // Updates only for individual prims and for the root object of a linkset.
1447 if (Linkset.IsRoot(this))
1448 {
1449 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1450 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1451 if (_vehicle.IsActive)
1452 {
1453 entprop.RotationalVelocity = OMV.Vector3.Zero;
1454 }
1455
1456 // Assign directly to the local variables so the normal set action does not happen
1457 _position = entprop.Position;
1458 _orientation = entprop.Rotation;
1459 _velocity = entprop.Velocity;
1460 _acceleration = entprop.Acceleration;
1461 _rotationalVelocity = entprop.RotationalVelocity;
1462
1463 // The sanity check can change the velocity and/or position.
1464 if (IsPhysical && PositionSanityCheck(true))
1465 {
1466 entprop.Position = _position;
1467 entprop.Velocity = _velocity;
1468 }
1469
1470 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1471 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1472 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1473
1474 // remember the current and last set values
1475 LastEntityProperties = CurrentEntityProperties;
1476 CurrentEntityProperties = entprop;
1477
1478 base.RequestPhysicsterseUpdate();
1479 }
1480 /*
1481 else
1482 {
1483 // For debugging, report the movement of children
1484 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1485 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1486 entprop.Acceleration, entprop.RotationalVelocity);
1487 }
1488 */
1489
1490 // The linkset implimentation might want to know about this.
1491 Linkset.UpdateProperties(this, true);
1492 }
1493}
1494}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs
new file mode 100644
index 0000000..1a7c34b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs
@@ -0,0 +1,957 @@
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.Runtime.InteropServices;
30using System.Text;
31using System.Threading;
32using OpenSim.Framework;
33using OpenSim.Region.Framework;
34using OpenSim.Region.CoreModules;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
36using OpenSim.Region.Physics.Manager;
37using Nini.Config;
38using log4net;
39using OpenMetaverse;
40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Based on material, set density and friction
43// More efficient memory usage when passing hull information from BSPrim to BulletSim
44// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
45// Implement LockAngularMotion
46// Add PID movement operations. What does ScenePresence.MoveToTarget do?
47// Check terrain size. 128 or 127?
48// Raycast
49//
50namespace OpenSim.Region.Physics.BulletSNPlugin
51{
52public sealed class BSScene : PhysicsScene, IPhysicsParameters
53{
54 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
55 private static readonly string LogHeader = "[BULLETS SCENE]";
56
57 // The name of the region we're working for.
58 public string RegionName { get; private set; }
59
60 public string BulletSimVersion = "?";
61
62 public Dictionary<uint, BSPhysObject> PhysObjects;
63 public BSShapeCollection Shapes;
64
65 // Keeping track of the objects with collisions so we can report begin and end of a collision
66 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
67 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
68 // Keep track of all the avatars so we can send them a collision event
69 // every tick so OpenSim will update its animation.
70 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
71
72 // let my minuions use my logger
73 public ILog Logger { get { return m_log; } }
74
75 public IMesher mesher;
76 public uint WorldID { get; private set; }
77 public BulletWorld World { get; private set; }
78
79 // All the constraints that have been allocated in this instance.
80 public BSConstraintCollection Constraints { get; private set; }
81
82 // Simulation parameters
83 internal int m_maxSubSteps;
84 internal float m_fixedTimeStep;
85 internal long m_simulationStep = 0;
86 public long SimulationStep { get { return m_simulationStep; } }
87 internal int m_taintsToProcessPerStep;
88 internal float LastTimeStep { get; private set; }
89
90 // Physical objects can register for prestep or poststep events
91 public delegate void PreStepAction(float timeStep);
92 public delegate void PostStepAction(float timeStep);
93 public event PreStepAction BeforeStep;
94 public event PreStepAction AfterStep;
95
96 // A value of the time now so all the collision and update routines do not have to get their own
97 // Set to 'now' just before all the prims and actors are called for collisions and updates
98 public int SimulationNowTime { get; private set; }
99
100 // True if initialized and ready to do simulation steps
101 private bool m_initialized = false;
102
103 // Flag which is true when processing taints.
104 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
105 public bool InTaintTime { get; private set; }
106
107 // Pinned memory used to pass step information between managed and unmanaged
108 internal int m_maxCollisionsPerFrame;
109 private List<BulletXNA.CollisionDesc> m_collisionArray;
110 //private GCHandle m_collisionArrayPinnedHandle;
111
112 internal int m_maxUpdatesPerFrame;
113 private List<BulletXNA.EntityProperties> m_updateArray;
114 //private GCHandle m_updateArrayPinnedHandle;
115
116
117 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
118 public const uint GROUNDPLANE_ID = 1;
119 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
120
121 public float SimpleWaterLevel { get; set; }
122 public BSTerrainManager TerrainManager { get; private set; }
123
124 public ConfigurationParameters Params
125 {
126 get { return UnmanagedParams[0]; }
127 }
128 public Vector3 DefaultGravity
129 {
130 get { return new Vector3(0f, 0f, Params.gravity); }
131 }
132 // Just the Z value of the gravity
133 public float DefaultGravityZ
134 {
135 get { return Params.gravity; }
136 }
137
138 // When functions in the unmanaged code must be called, it is only
139 // done at a known time just before the simulation step. The taint
140 // system saves all these function calls and executes them in
141 // order before the simulation.
142 public delegate void TaintCallback();
143 private struct TaintCallbackEntry
144 {
145 public String ident;
146 public TaintCallback callback;
147 public TaintCallbackEntry(string i, TaintCallback c)
148 {
149 ident = i;
150 callback = c;
151 }
152 }
153 private Object _taintLock = new Object(); // lock for using the next object
154 private List<TaintCallbackEntry> _taintOperations;
155 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
156 private List<TaintCallbackEntry> _postStepOperations;
157
158 // A pointer to an instance if this structure is passed to the C++ code
159 // Used to pass basic configuration values to the unmanaged code.
160 internal ConfigurationParameters[] UnmanagedParams;
161 //GCHandle m_paramsHandle;
162
163 // Handle to the callback used by the unmanaged code to call into the managed code.
164 // Used for debug logging.
165 // Need to store the handle in a persistant variable so it won't be freed.
166 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
167
168 // Sometimes you just have to log everything.
169 public Logging.LogWriter PhysicsLogging;
170 private bool m_physicsLoggingEnabled;
171 private string m_physicsLoggingDir;
172 private string m_physicsLoggingPrefix;
173 private int m_physicsLoggingFileMinutes;
174 private bool m_physicsLoggingDoFlush;
175 // 'true' of the vehicle code is to log lots of details
176 public bool VehicleLoggingEnabled { get; private set; }
177 public bool VehiclePhysicalLoggingEnabled { get; private set; }
178
179 #region Construction and Initialization
180 public BSScene(string identifier)
181 {
182 m_initialized = false;
183 // we are passed the name of the region we're working for.
184 RegionName = identifier;
185 }
186
187 public override void Initialise(IMesher meshmerizer, IConfigSource config)
188 {
189 mesher = meshmerizer;
190 _taintOperations = new List<TaintCallbackEntry>();
191 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
192 _postStepOperations = new List<TaintCallbackEntry>();
193 PhysObjects = new Dictionary<uint, BSPhysObject>();
194 Shapes = new BSShapeCollection(this);
195
196 // Allocate pinned memory to pass parameters.
197 UnmanagedParams = new ConfigurationParameters[1];
198 //m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned);
199
200 // Set default values for physics parameters plus any overrides from the ini file
201 GetInitialParameterValues(config);
202
203 // allocate more pinned memory close to the above in an attempt to get the memory all together
204 m_collisionArray = new List<BulletXNA.CollisionDesc>();
205 //m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
206 m_updateArray = new List<BulletXNA.EntityProperties>();
207 //m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
208
209 // Enable very detailed logging.
210 // By creating an empty logger when not logging, the log message invocation code
211 // can be left in and every call doesn't have to check for null.
212 if (m_physicsLoggingEnabled)
213 {
214 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
215 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
216 }
217 else
218 {
219 PhysicsLogging = new Logging.LogWriter();
220 }
221
222 // If Debug logging level, enable logging from the unmanaged code
223 m_DebugLogCallbackHandle = null;
224 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
225 {
226 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
227 if (PhysicsLogging.Enabled)
228 // The handle is saved in a variable to make sure it doesn't get freed after this call
229 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
230 else
231 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
232 }
233
234 // Get the version of the DLL
235 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
236 // BulletSimVersion = BulletSimAPI.GetVersion();
237 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
238
239 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
240 // a child in a mega-region.
241 // Bullet actually doesn't care about the extents of the simulated
242 // area. It tracks active objects no matter where they are.
243 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
244
245 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
246
247 World = new BulletWorld(0, this, BulletSimAPI.Initialize2(worldExtent, UnmanagedParams,
248 m_maxCollisionsPerFrame, ref m_collisionArray,
249 m_maxUpdatesPerFrame,ref m_updateArray,
250 m_DebugLogCallbackHandle));
251
252 Constraints = new BSConstraintCollection(World);
253
254 TerrainManager = new BSTerrainManager(this);
255 TerrainManager.CreateInitialGroundPlaneAndTerrain();
256
257 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
258
259 InTaintTime = false;
260 m_initialized = true;
261 }
262
263 // All default parameter values are set here. There should be no values set in the
264 // variable definitions.
265 private void GetInitialParameterValues(IConfigSource config)
266 {
267 ConfigurationParameters parms = new ConfigurationParameters();
268 UnmanagedParams[0] = parms;
269
270 BSParam.SetParameterDefaultValues(this);
271
272 if (config != null)
273 {
274 // If there are specifications in the ini file, use those values
275 IConfig pConfig = config.Configs["BulletSim"];
276 if (pConfig != null)
277 {
278 BSParam.SetParameterConfigurationValues(this, pConfig);
279
280 // Very detailed logging for physics debugging
281 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
282 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
283 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
284 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
285 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
286 // Very detailed logging for vehicle debugging
287 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
288 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
289
290 // Do any replacements in the parameters
291 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
292 }
293
294 // The material characteristics.
295 BSMaterials.InitializeFromDefaults(Params);
296 if (pConfig != null)
297 {
298 // Let the user add new and interesting material property values.
299 BSMaterials.InitializefromParameters(pConfig);
300 }
301 }
302 }
303
304 // A helper function that handles a true/false parameter and returns the proper float number encoding
305 float ParamBoolean(IConfig config, string parmName, float deflt)
306 {
307 float ret = deflt;
308 if (config.Contains(parmName))
309 {
310 ret = ConfigurationParameters.numericFalse;
311 if (config.GetBoolean(parmName, false))
312 {
313 ret = ConfigurationParameters.numericTrue;
314 }
315 }
316 return ret;
317 }
318
319 // Called directly from unmanaged code so don't do much
320 private void BulletLogger(string msg)
321 {
322 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
323 }
324
325 // Called directly from unmanaged code so don't do much
326 private void BulletLoggerPhysLog(string msg)
327 {
328 DetailLog("[BULLETS UNMANAGED]:" + msg);
329 }
330
331 public override void Dispose()
332 {
333 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
334
335 // make sure no stepping happens while we're deleting stuff
336 m_initialized = false;
337
338 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
339 {
340 kvp.Value.Destroy();
341 }
342 PhysObjects.Clear();
343
344 // Now that the prims are all cleaned up, there should be no constraints left
345 if (Constraints != null)
346 {
347 Constraints.Dispose();
348 Constraints = null;
349 }
350
351 if (Shapes != null)
352 {
353 Shapes.Dispose();
354 Shapes = null;
355 }
356
357 if (TerrainManager != null)
358 {
359 TerrainManager.ReleaseGroundPlaneAndTerrain();
360 TerrainManager.Dispose();
361 TerrainManager = null;
362 }
363
364 // Anything left in the unmanaged code should be cleaned out
365 BulletSimAPI.Shutdown2(World.ptr);
366
367 // Not logging any more
368 PhysicsLogging.Close();
369 }
370 #endregion // Construction and Initialization
371
372 #region Prim and Avatar addition and removal
373
374 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
375 {
376 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
377 return null;
378 }
379
380 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
381 {
382 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
383
384 if (!m_initialized) return null;
385
386 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
387 lock (PhysObjects) PhysObjects.Add(localID, actor);
388
389 // TODO: Remove kludge someday.
390 // We must generate a collision for avatars whether they collide or not.
391 // This is required by OpenSim to update avatar animations, etc.
392 lock (m_avatars) m_avatars.Add(actor);
393
394 return actor;
395 }
396
397 public override void RemoveAvatar(PhysicsActor actor)
398 {
399 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
400
401 if (!m_initialized) return;
402
403 BSCharacter bsactor = actor as BSCharacter;
404 if (bsactor != null)
405 {
406 try
407 {
408 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
409 // Remove kludge someday
410 lock (m_avatars) m_avatars.Remove(bsactor);
411 }
412 catch (Exception e)
413 {
414 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
415 }
416 bsactor.Destroy();
417 // bsactor.dispose();
418 }
419 }
420
421 public override void RemovePrim(PhysicsActor prim)
422 {
423 if (!m_initialized) return;
424
425 BSPrim bsprim = prim as BSPrim;
426 if (bsprim != null)
427 {
428 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
429 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
430 try
431 {
432 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
433 }
434 catch (Exception e)
435 {
436 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
437 }
438 bsprim.Destroy();
439 // bsprim.dispose();
440 }
441 else
442 {
443 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
444 }
445 }
446
447 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
448 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
449 {
450 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
451
452 if (!m_initialized) return null;
453
454 DetailLog("{0},AddPrimShape,call", localID);
455
456 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
457 lock (PhysObjects) PhysObjects.Add(localID, prim);
458 return prim;
459 }
460
461 // This is a call from the simulator saying that some physical property has been updated.
462 // The BulletSim driver senses the changing of relevant properties so this taint
463 // information call is not needed.
464 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
465
466 #endregion // Prim and Avatar addition and removal
467
468 #region Simulation
469 // Simulate one timestep
470 public override float Simulate(float timeStep)
471 {
472 // prevent simulation until we've been initialized
473 if (!m_initialized) return 5.0f;
474
475 LastTimeStep = timeStep;
476
477 int updatedEntityCount = 0;
478 //Object updatedEntitiesPtr;
479 int collidersCount = 0;
480 //Object collidersPtr;
481
482 int beforeTime = 0;
483 int simTime = 0;
484
485 // update the prim states while we know the physics engine is not busy
486 int numTaints = _taintOperations.Count;
487
488 InTaintTime = true; // Only used for debugging so locking is not necessary.
489
490 ProcessTaints();
491
492 // Some of the physical objects requre individual, pre-step calls
493 TriggerPreStepEvent(timeStep);
494
495 // the prestep actions might have added taints
496 ProcessTaints();
497
498 InTaintTime = false; // Only used for debugging so locking is not necessary.
499
500 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
501 // Only enable this in a limited test world with few objects.
502 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
503
504 // step the physical world one interval
505 m_simulationStep++;
506 int numSubSteps = 0;
507
508 try
509 {
510 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
511
512 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
513 out updatedEntityCount, out m_updateArray, out collidersCount, out m_collisionArray);
514
515 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
516 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
517 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
518 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
519 }
520 catch (Exception e)
521 {
522 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
523 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
524 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
525 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
526 updatedEntityCount = 0;
527 collidersCount = 0;
528 }
529
530 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
531
532 // Get a value for 'now' so all the collision and update routines don't have to get their own.
533 SimulationNowTime = Util.EnvironmentTickCount();
534
535 // If there were collisions, process them by sending the event to the prim.
536 // Collisions must be processed before updates.
537 if (collidersCount > 0)
538 {
539 for (int ii = 0; ii < collidersCount; ii++)
540 {
541 uint cA = m_collisionArray[ii].aID;
542 uint cB = m_collisionArray[ii].bID;
543 Vector3 point = new Vector3(m_collisionArray[ii].point.X, m_collisionArray[ii].point.Y,
544 m_collisionArray[ii].point.Z);
545 Vector3 normal = new Vector3(m_collisionArray[ii].normal.X, m_collisionArray[ii].normal.Y,
546 m_collisionArray[ii].normal.Z);
547 SendCollision(cA, cB, point, normal, 0.01f);
548 SendCollision(cB, cA, point, -normal, 0.01f);
549 }
550 }
551
552 // The above SendCollision's batch up the collisions on the objects.
553 // Now push the collisions into the simulator.
554 if (ObjectsWithCollisions.Count > 0)
555 {
556 foreach (BSPhysObject bsp in ObjectsWithCollisions)
557 if (!bsp.SendCollisions())
558 {
559 // If the object is done colliding, see that it's removed from the colliding list
560 ObjectsWithNoMoreCollisions.Add(bsp);
561 }
562 }
563
564 // This is a kludge to get avatar movement updates.
565 // The simulator expects collisions for avatars even if there are have been no collisions.
566 // The event updates avatar animations and stuff.
567 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
568 foreach (BSPhysObject bsp in m_avatars)
569 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
570 bsp.SendCollisions();
571
572 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
573 // Not done above because it is inside an iteration of ObjectWithCollisions.
574 // This complex collision processing is required to create an empty collision
575 // event call after all collisions have happened on an object. This enables
576 // the simulator to generate the 'collision end' event.
577 if (ObjectsWithNoMoreCollisions.Count > 0)
578 {
579 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
580 ObjectsWithCollisions.Remove(po);
581 ObjectsWithNoMoreCollisions.Clear();
582 }
583 // Done with collisions.
584
585 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
586 if (updatedEntityCount > 0)
587 {
588 for (int ii = 0; ii < updatedEntityCount; ii++)
589 {
590
591 BulletXNA.EntityProperties entprop = m_updateArray[ii];
592 BSPhysObject pobj;
593 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
594 {
595 EntityProperties prop = new EntityProperties()
596 {
597 Acceleration = new Vector3(entprop.Acceleration.X, entprop.Acceleration.Y, entprop.Acceleration.Z),
598 ID = entprop.ID,
599 Position = new Vector3(entprop.Position.X,entprop.Position.Y,entprop.Position.Z),
600 Rotation = new Quaternion(entprop.Rotation.X,entprop.Rotation.Y,entprop.Rotation.Z,entprop.Rotation.W),
601 RotationalVelocity = new Vector3(entprop.AngularVelocity.X,entprop.AngularVelocity.Y,entprop.AngularVelocity.Z),
602 Velocity = new Vector3(entprop.Velocity.X,entprop.Velocity.Y,entprop.Velocity.Z)
603 };
604 //m_log.Debug(pobj.Name + ":" + prop.ToString() + "\n");
605 pobj.UpdateProperties(prop);
606 }
607 }
608 }
609
610 TriggerPostStepEvent(timeStep);
611
612 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
613 // Only enable this in a limited test world with few objects.
614 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
615
616 // The physics engine returns the number of milliseconds it simulated this call.
617 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
618 // Multiply by 55 to give a nominal frame rate of 55.
619 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
620 }
621
622 // Something has collided
623 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
624 {
625 if (localID <= TerrainManager.HighestTerrainID)
626 {
627 return; // don't send collisions to the terrain
628 }
629
630 BSPhysObject collider;
631 if (!PhysObjects.TryGetValue(localID, out collider))
632 {
633 // If the object that is colliding cannot be found, just ignore the collision.
634 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
635 return;
636 }
637
638 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
639 BSPhysObject collidee = null;
640 PhysObjects.TryGetValue(collidingWith, out collidee);
641
642 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
643
644 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
645 {
646 // If a collision was posted, remember to send it to the simulator
647 ObjectsWithCollisions.Add(collider);
648 }
649
650 return;
651 }
652
653 #endregion // Simulation
654
655 public override void GetResults() { }
656
657 #region Terrain
658
659 public override void SetTerrain(float[] heightMap) {
660 TerrainManager.SetTerrain(heightMap);
661 }
662
663 public override void SetWaterLevel(float baseheight)
664 {
665 SimpleWaterLevel = baseheight;
666 }
667
668 public override void DeleteTerrain()
669 {
670 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
671 }
672
673 // Although no one seems to check this, I do support combining.
674 public override bool SupportsCombining()
675 {
676 return TerrainManager.SupportsCombining();
677 }
678 // This call says I am a child to region zero in a mega-region. 'pScene' is that
679 // of region zero, 'offset' is my offset from regions zero's origin, and
680 // 'extents' is the largest XY that is handled in my region.
681 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
682 {
683 TerrainManager.Combine(pScene, offset, extents);
684 }
685
686 // Unhook all the combining that I know about.
687 public override void UnCombine(PhysicsScene pScene)
688 {
689 TerrainManager.UnCombine(pScene);
690 }
691
692 #endregion // Terrain
693
694 public override Dictionary<uint, float> GetTopColliders()
695 {
696 return new Dictionary<uint, float>();
697 }
698
699 public override bool IsThreaded { get { return false; } }
700
701 #region Taints
702 // The simulation execution order is:
703 // Simulate()
704 // DoOneTimeTaints
705 // TriggerPreStepEvent
706 // DoOneTimeTaints
707 // Step()
708 // ProcessAndForwardCollisions
709 // ProcessAndForwardPropertyUpdates
710 // TriggerPostStepEvent
711
712 // Calls to the PhysicsActors can't directly call into the physics engine
713 // because it might be busy. We delay changes to a known time.
714 // We rely on C#'s closure to save and restore the context for the delegate.
715 public void TaintedObject(String ident, TaintCallback callback)
716 {
717 if (!m_initialized) return;
718
719 lock (_taintLock)
720 {
721 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
722 }
723
724 return;
725 }
726
727 // Sometimes a potentially tainted operation can be used in and out of taint time.
728 // This routine executes the command immediately if in taint-time otherwise it is queued.
729 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
730 {
731 if (inTaintTime)
732 callback();
733 else
734 TaintedObject(ident, callback);
735 }
736
737 private void TriggerPreStepEvent(float timeStep)
738 {
739 PreStepAction actions = BeforeStep;
740 if (actions != null)
741 actions(timeStep);
742
743 }
744
745 private void TriggerPostStepEvent(float timeStep)
746 {
747 PreStepAction actions = AfterStep;
748 if (actions != null)
749 actions(timeStep);
750
751 }
752
753 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
754 // a callback into itself to do the actual property change. That callback is called
755 // here just before the physics engine is called to step the simulation.
756 public void ProcessTaints()
757 {
758 ProcessRegularTaints();
759 ProcessPostTaintTaints();
760 }
761
762 private void ProcessRegularTaints()
763 {
764 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
765 {
766 // swizzle a new list into the list location so we can process what's there
767 List<TaintCallbackEntry> oldList;
768 lock (_taintLock)
769 {
770 oldList = _taintOperations;
771 _taintOperations = new List<TaintCallbackEntry>();
772 }
773
774 foreach (TaintCallbackEntry tcbe in oldList)
775 {
776 try
777 {
778 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
779 tcbe.callback();
780 }
781 catch (Exception e)
782 {
783 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
784 }
785 }
786 oldList.Clear();
787 }
788 }
789
790 // Schedule an update to happen after all the regular taints are processed.
791 // Note that new requests for the same operation ("ident") for the same object ("ID")
792 // will replace any previous operation by the same object.
793 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
794 {
795 string uniqueIdent = ident + "-" + ID.ToString();
796 lock (_taintLock)
797 {
798 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
799 }
800
801 return;
802 }
803
804 // Taints that happen after the normal taint processing but before the simulation step.
805 private void ProcessPostTaintTaints()
806 {
807 if (_postTaintOperations.Count > 0)
808 {
809 Dictionary<string, TaintCallbackEntry> oldList;
810 lock (_taintLock)
811 {
812 oldList = _postTaintOperations;
813 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
814 }
815
816 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
817 {
818 try
819 {
820 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
821 kvp.Value.callback();
822 }
823 catch (Exception e)
824 {
825 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
826 }
827 }
828 oldList.Clear();
829 }
830 }
831
832 // Only used for debugging. Does not change state of anything so locking is not necessary.
833 public bool AssertInTaintTime(string whereFrom)
834 {
835 if (!InTaintTime)
836 {
837 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
838 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
839 Util.PrintCallStack(DetailLog);
840 }
841 return InTaintTime;
842 }
843
844 #endregion // Taints
845
846 #region INI and command line parameter processing
847
848 #region IPhysicsParameters
849 // Get the list of parameters this physics engine supports
850 public PhysParameterEntry[] GetParameterList()
851 {
852 BSParam.BuildParameterTable();
853 return BSParam.SettableParameters;
854 }
855
856 // Set parameter on a specific or all instances.
857 // Return 'false' if not able to set the parameter.
858 // Setting the value in the m_params block will change the value the physics engine
859 // will use the next time since it's pinned and shared memory.
860 // Some of the values require calling into the physics engine to get the new
861 // value activated ('terrainFriction' for instance).
862 public bool SetPhysicsParameter(string parm, float val, uint localID)
863 {
864 bool ret = false;
865 BSParam.ParameterDefn theParam;
866 if (BSParam.TryGetParameter(parm, out theParam))
867 {
868 theParam.setter(this, parm, localID, val);
869 ret = true;
870 }
871 return ret;
872 }
873
874 // update all the localIDs specified
875 // If the local ID is APPLY_TO_NONE, just change the default value
876 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
877 // If the localID is a specific object, apply the parameter change to only that object
878 internal delegate void AssignVal(float x);
879 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
880 {
881 List<uint> objectIDs = new List<uint>();
882 switch (localID)
883 {
884 case PhysParameterEntry.APPLY_TO_NONE:
885 setDefault(val); // setting only the default value
886 // This will cause a call into the physical world if some operation is specified (SetOnObject).
887 objectIDs.Add(TERRAIN_ID);
888 TaintedUpdateParameter(parm, objectIDs, val);
889 break;
890 case PhysParameterEntry.APPLY_TO_ALL:
891 setDefault(val); // setting ALL also sets the default value
892 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
893 TaintedUpdateParameter(parm, objectIDs, val);
894 break;
895 default:
896 // setting only one localID
897 objectIDs.Add(localID);
898 TaintedUpdateParameter(parm, objectIDs, val);
899 break;
900 }
901 }
902
903 // schedule the actual updating of the paramter to when the phys engine is not busy
904 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
905 {
906 float xval = val;
907 List<uint> xlIDs = lIDs;
908 string xparm = parm;
909 TaintedObject("BSScene.UpdateParameterSet", delegate() {
910 BSParam.ParameterDefn thisParam;
911 if (BSParam.TryGetParameter(xparm, out thisParam))
912 {
913 if (thisParam.onObject != null)
914 {
915 foreach (uint lID in xlIDs)
916 {
917 BSPhysObject theObject = null;
918 PhysObjects.TryGetValue(lID, out theObject);
919 thisParam.onObject(this, theObject, xval);
920 }
921 }
922 }
923 });
924 }
925
926 // Get parameter.
927 // Return 'false' if not able to get the parameter.
928 public bool GetPhysicsParameter(string parm, out float value)
929 {
930 float val = 0f;
931 bool ret = false;
932 BSParam.ParameterDefn theParam;
933 if (BSParam.TryGetParameter(parm, out theParam))
934 {
935 val = theParam.getter(this);
936 ret = true;
937 }
938 value = val;
939 return ret;
940 }
941
942 #endregion IPhysicsParameters
943
944 #endregion Runtime settable parameters
945
946 // Invoke the detailed logger and output something if it's enabled.
947 public void DetailLog(string msg, params Object[] args)
948 {
949 PhysicsLogging.Write(msg, args);
950 // Add the Flush() if debugging crashes. Gets all the messages written out.
951 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
952 }
953 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
954 public const string DetailLogZero = "0000000000";
955
956}
957}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs
new file mode 100644
index 0000000..764aece
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs
@@ -0,0 +1,1015 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37public sealed class BSShapeCollection : IDisposable
38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 private BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public Object ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public Object ptr;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false;
69
70 public BSShapeCollection(BSScene physScene)
71 {
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;
78 }
79
80 public void Dispose()
81 {
82 // TODO!!!!!!!!!
83 }
84
85 // Callbacks called just before either the body or shape is destroyed.
86 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91
92 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes
94 // sure the body is of the right type.
95 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
97 // the current shape or body is destroyed. This allows the caller to remove any
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105
106 bool ret = false;
107
108 // This lock could probably be pushed down lower but building shouldn't take long
109 lock (m_collectionActivityLock)
110 {
111 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
115 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
120 prim.PhysShape, bodyCallback);
121 ret = newGeom || newBody;
122 }
123 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
124 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
125
126 return ret;
127 }
128
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
134 // Track another user of a body.
135 // We presume the caller has allocated the body.
136 // Bodies only have one user so the body is just put into the world if not already there.
137 public void ReferenceBody(BulletBody body, bool inTaintTime)
138 {
139 lock (m_collectionActivityLock)
140 {
141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
143 {
144 if (!BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
145 {
146 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
148 }
149 });
150 }
151 }
152
153 // Release the usage of a body.
154 // Called when releasing use of a BSBody. BSShape is handled separately.
155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
156 {
157 if (!body.HasPhysicalBody)
158 return;
159
160 lock (m_collectionActivityLock)
161 {
162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
163 {
164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
165 body.ID, body, inTaintTime);
166 // If the caller needs to know the old body is going away, pass the event up.
167 if (bodyCallback != null) bodyCallback(body);
168
169 if (BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
170 {
171 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
173 }
174
175 // Zero any reference to the shape so it is not freed when the body is deleted.
176 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, null);
177 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
178 });
179 }
180 }
181
182 // Track the datastructures and use count for a shape.
183 // When creating a hull, this is called first to reference the mesh
184 // and then again to reference the hull.
185 // Meshes and hulls for the same shape have the same hash key.
186 // NOTE that native shapes are not added to the mesh list or removed.
187 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
188 public bool ReferenceShape(BulletShape shape)
189 {
190 bool ret = false;
191 switch (shape.type)
192 {
193 case BSPhysicsShapeType.SHAPE_MESH:
194 MeshDesc meshDesc;
195 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
196 {
197 // There is an existing instance of this mesh.
198 meshDesc.referenceCount++;
199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
201 }
202 else
203 {
204 // This is a new reference to a mesh
205 meshDesc.ptr = shape.ptr;
206 meshDesc.shapeKey = shape.shapeKey;
207 // We keep a reference to the underlying IMesh data so a hull can be built
208 meshDesc.referenceCount = 1;
209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
211 ret = true;
212 }
213 meshDesc.lastReferenced = System.DateTime.Now;
214 Meshes[shape.shapeKey] = meshDesc;
215 break;
216 case BSPhysicsShapeType.SHAPE_HULL:
217 HullDesc hullDesc;
218 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
219 {
220 // There is an existing instance of this hull.
221 hullDesc.referenceCount++;
222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
224 }
225 else
226 {
227 // This is a new reference to a hull
228 hullDesc.ptr = shape.ptr;
229 hullDesc.shapeKey = shape.shapeKey;
230 hullDesc.referenceCount = 1;
231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
233 ret = true;
234
235 }
236 hullDesc.lastReferenced = System.DateTime.Now;
237 Hulls[shape.shapeKey] = hullDesc;
238 break;
239 case BSPhysicsShapeType.SHAPE_UNKNOWN:
240 break;
241 default:
242 // Native shapes are not tracked and they don't go into any list
243 break;
244 }
245 return ret;
246 }
247
248 // Release the usage of a shape.
249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
250 {
251 if (!shape.HasPhysicalShape)
252 return;
253
254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
255 {
256 if (shape.HasPhysicalShape)
257 {
258 if (shape.isNativeShape)
259 {
260 // Native shapes are not tracked and are released immediately
261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
262 BSScene.DetailLogZero, shape.ptr.ToString(), inTaintTime);
263 if (shapeCallback != null) shapeCallback(shape);
264 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
265 }
266 else
267 {
268 switch (shape.type)
269 {
270 case BSPhysicsShapeType.SHAPE_HULL:
271 DereferenceHull(shape, shapeCallback);
272 break;
273 case BSPhysicsShapeType.SHAPE_MESH:
274 DereferenceMesh(shape, shapeCallback);
275 break;
276 case BSPhysicsShapeType.SHAPE_COMPOUND:
277 DereferenceCompound(shape, shapeCallback);
278 break;
279 case BSPhysicsShapeType.SHAPE_UNKNOWN:
280 break;
281 default:
282 break;
283 }
284 }
285 }
286 });
287 }
288
289 // Count down the reference count for a mesh shape
290 // Called at taint-time.
291 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
292 {
293 MeshDesc meshDesc;
294 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
295 {
296 meshDesc.referenceCount--;
297 // TODO: release the Bullet storage
298 if (shapeCallback != null) shapeCallback(shape);
299 meshDesc.lastReferenced = System.DateTime.Now;
300 Meshes[shape.shapeKey] = meshDesc;
301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
303
304 }
305 }
306
307 // Count down the reference count for a hull shape
308 // Called at taint-time.
309 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
310 {
311 HullDesc hullDesc;
312 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
313 {
314 hullDesc.referenceCount--;
315 // TODO: release the Bullet storage (aging old entries?)
316
317 // Tell upper layers that, if they have dependencies on this shape, this link is going away
318 if (shapeCallback != null) shapeCallback(shape);
319
320 hullDesc.lastReferenced = System.DateTime.Now;
321 Hulls[shape.shapeKey] = hullDesc;
322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
324 }
325 }
326
327 // Remove a reference to a compound shape.
328 // Taking a compound shape apart is a little tricky because if you just delete the
329 // physical shape, it will free all the underlying children. We can't do that because
330 // they could be shared. So, this removes each of the children from the compound and
331 // dereferences them separately before destroying the compound collision object itself.
332 // Called at taint-time.
333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
334 {
335 if (!BulletSimAPI.IsCompound2(shape.ptr))
336 {
337 // Failed the sanity check!!
338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
339 LogHeader, shape.type, shape.ptr.ToString());
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
341 BSScene.DetailLogZero, shape.type, shape.ptr.ToString());
342 return;
343 }
344
345 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
347
348 for (int ii = numChildren - 1; ii >= 0; ii--)
349 {
350 Object childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
351 DereferenceAnonCollisionShape(childShape);
352 }
353 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
354 }
355
356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
357 // Figure out type and call the correct dereference routine.
358 // Called at taint-time.
359 private void DereferenceAnonCollisionShape(Object cShape)
360 {
361 MeshDesc meshDesc;
362 HullDesc hullDesc;
363
364 BulletShape shapeInfo = new BulletShape(cShape);
365 if (TryGetMeshByPtr(cShape, out meshDesc))
366 {
367 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
368 shapeInfo.shapeKey = meshDesc.shapeKey;
369 }
370 else
371 {
372 if (TryGetHullByPtr(cShape, out hullDesc))
373 {
374 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
375 shapeInfo.shapeKey = hullDesc.shapeKey;
376 }
377 else
378 {
379 if (BulletSimAPI.IsCompound2(cShape))
380 {
381 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
382 }
383 else
384 {
385 if (BulletSimAPI.IsNativeShape2(cShape))
386 {
387 shapeInfo.isNativeShape = true;
388 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
389 }
390 }
391 }
392 }
393
394 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
395
396 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
397 {
398 DereferenceShape(shapeInfo, true, null);
399 }
400 else
401 {
402 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
403 LogHeader, PhysicsScene.RegionName, cShape.ToString());
404 }
405 }
406
407 // Create the geometry information in Bullet for later use.
408 // The objects needs a hull if it's physical otherwise a mesh is enough.
409 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
410 // shared geometries will be used. If the parameters of the existing shape are the same
411 // as this request, the shape is not rebuilt.
412 // Info in prim.BSShape is updated to the new shape.
413 // Returns 'true' if the geometry was rebuilt.
414 // Called at taint-time!
415 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
416 {
417 bool ret = false;
418 bool haveShape = false;
419
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
421 {
422 // an avatar capsule is close to a native shape (it is not shared)
423 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
424 FixedShapeKey.KEY_CAPSULE, shapeCallback);
425 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
426 ret = true;
427 haveShape = true;
428 }
429
430 // Compound shapes are handled special as they are rebuilt from scratch.
431 // This isn't too great a hardship since most of the child shapes will have already been created.
432 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
433 {
434 ret = GetReferenceToCompoundShape(prim, shapeCallback);
435 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
436 haveShape = true;
437 }
438
439 if (!haveShape)
440 {
441 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
442 }
443
444 return ret;
445 }
446
447 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
448 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
449 {
450 bool ret = false;
451 bool haveShape = false;
452 bool nativeShapePossible = true;
453 PrimitiveBaseShape pbs = prim.BaseShape;
454
455 // If the prim attributes are simple, this could be a simple Bullet native shape
456 if (!haveShape
457 && pbs != null
458 && nativeShapePossible
459 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
460 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
461 && pbs.ProfileHollow == 0
462 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
463 && pbs.PathBegin == 0 && pbs.PathEnd == 0
464 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
465 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
466 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
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
476 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
477 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
478 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
479 {
480 haveShape = true;
481 if (forceRebuild
482 || prim.Scale != scaleOfExistingShape
483 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
484 )
485 {
486 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
487 FixedShapeKey.KEY_SPHERE, shapeCallback);
488 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
489 prim.LocalID, forceRebuild, prim.PhysShape);
490 }
491 }
492 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
493 {
494 haveShape = true;
495 if (forceRebuild
496 || prim.Scale != scaleOfExistingShape
497 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
498 )
499 {
500 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
501 FixedShapeKey.KEY_BOX, shapeCallback);
502 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
503 prim.LocalID, forceRebuild, prim.PhysShape);
504 }
505 }
506 }
507
508 // If a simple shape is not happening, create a mesh and possibly a hull.
509 if (!haveShape && pbs != null)
510 {
511 ret = CreateGeomMeshOrHull(prim, shapeCallback);
512 }
513
514 return ret;
515 }
516
517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
518 {
519
520 bool ret = false;
521 // Note that if it's a native shape, the check for physical/non-physical is not
522 // made. Native shapes work in either case.
523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
524 {
525 // Update prim.BSShape to reference a hull of this shape.
526 ret = GetReferenceToHull(prim,shapeCallback);
527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
529 }
530 else
531 {
532 ret = GetReferenceToMesh(prim, shapeCallback);
533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
535 }
536 return ret;
537 }
538
539 // Creates a native shape and assignes it to prim.BSShape.
540 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
541 private bool GetReferenceToNativeShape(BSPhysObject prim,
542 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
543 ShapeDestructionCallback shapeCallback)
544 {
545 // release any previous shape
546 DereferenceShape(prim.PhysShape, true, shapeCallback);
547
548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
549
550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
552 prim.LocalID, newShape, prim.Scale);
553
554 // native shapes are scaled by Bullet
555 prim.PhysShape = newShape;
556 return true;
557 }
558
559 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
560 FixedShapeKey shapeKey)
561 {
562 BulletShape newShape;
563 // Need to make sure the passed shape information is for the native type.
564 ShapeData nativeShapeData = new ShapeData();
565 nativeShapeData.Type = shapeType;
566 nativeShapeData.ID = prim.LocalID;
567 nativeShapeData.Scale = prim.Scale;
568 nativeShapeData.Size = prim.Scale; // unneeded, I think.
569 nativeShapeData.MeshKey = (ulong)shapeKey;
570 nativeShapeData.HullKey = (ulong)shapeKey;
571
572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
573 {
574 // The proper scale has been calculated in the prim.
575 newShape = new BulletShape(
576 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
577 , shapeType);
578 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
579 }
580 else
581 {
582 // Native shapes are scaled in Bullet so set the scaling to the size
583 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
584 }
585 if (!newShape.HasPhysicalShape)
586 {
587 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
588 LogHeader, prim.LocalID, shapeType);
589 }
590 newShape.shapeKey = (System.UInt64)shapeKey;
591 newShape.isNativeShape = true;
592
593 return newShape;
594 }
595
596 // Builds a mesh shape in the physical world and updates prim.BSShape.
597 // Dereferences previous shape in BSShape and adds a reference for this new shape.
598 // Returns 'true' of a mesh was actually built. Otherwise .
599 // Called at taint-time!
600 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
601 {
602 BulletShape newShape = new BulletShape();
603
604 float lod;
605 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
606
607 // if this new shape is the same as last time, don't recreate the mesh
608 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
609 return false;
610
611 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
612 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
613
614 // Since we're recreating new, get rid of the reference to the previous shape
615 DereferenceShape(prim.PhysShape, true, shapeCallback);
616
617 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
618 // Take evasive action if the mesh was not constructed.
619 newShape = VerifyMeshCreated(newShape, prim);
620
621 ReferenceShape(newShape);
622
623 prim.PhysShape = newShape;
624
625 return true; // 'true' means a new shape has been added to this prim
626 }
627
628 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
629 {
630 IMesh meshData = null;
631 Object meshPtr = null;
632 MeshDesc meshDesc;
633 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
634 {
635 // If the mesh has already been built just use it.
636 meshPtr = meshDesc.ptr;
637 }
638 else
639 {
640 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
641
642 if (meshData != null)
643 {
644 int[] indices = meshData.getIndexListAsInt();
645 List<OMV.Vector3> vertices = meshData.getVertexList();
646
647 float[] verticesAsFloats = new float[vertices.Count * 3];
648 int vi = 0;
649 foreach (OMV.Vector3 vv in vertices)
650 {
651 verticesAsFloats[vi++] = vv.X;
652 verticesAsFloats[vi++] = vv.Y;
653 verticesAsFloats[vi++] = vv.Z;
654 }
655
656 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
657 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
658
659 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
660 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
661 }
662 }
663 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
664 newShape.shapeKey = newMeshKey;
665
666 return newShape;
667 }
668
669 // See that hull shape exists in the physical world and update prim.BSShape.
670 // We could be creating the hull because scale changed or whatever.
671 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
672 {
673 BulletShape newShape;
674
675 float lod;
676 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
677
678 // if the hull hasn't changed, don't rebuild it
679 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
680 return false;
681
682 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
683 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
684
685 // Remove usage of the previous shape.
686 DereferenceShape(prim.PhysShape, true, shapeCallback);
687
688 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
689 newShape = VerifyMeshCreated(newShape, prim);
690
691 ReferenceShape(newShape);
692
693 prim.PhysShape = newShape;
694 return true; // 'true' means a new shape has been added to this prim
695 }
696
697 List<ConvexResult> m_hulls;
698 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
699 {
700
701 Object hullPtr = null;
702 HullDesc hullDesc;
703 if (Hulls.TryGetValue(newHullKey, out hullDesc))
704 {
705 // If the hull shape already is created, just use it.
706 hullPtr = hullDesc.ptr;
707 }
708 else
709 {
710 // Build a new hull in the physical world
711 // Pass true for physicalness as this creates some sort of bounding box which we don't need
712 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
713 if (meshData != null)
714 {
715
716 int[] indices = meshData.getIndexListAsInt();
717 List<OMV.Vector3> vertices = meshData.getVertexList();
718
719 //format conversion from IMesh format to DecompDesc format
720 List<int> convIndices = new List<int>();
721 List<float3> convVertices = new List<float3>();
722 for (int ii = 0; ii < indices.GetLength(0); ii++)
723 {
724 convIndices.Add(indices[ii]);
725 }
726 foreach (OMV.Vector3 vv in vertices)
727 {
728 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
729 }
730
731 // setup and do convex hull conversion
732 m_hulls = new List<ConvexResult>();
733 DecompDesc dcomp = new DecompDesc();
734 dcomp.mIndices = convIndices;
735 dcomp.mVertices = convVertices;
736 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
737 // create the hull into the _hulls variable
738 convexBuilder.process(dcomp);
739
740 // Convert the vertices and indices for passing to unmanaged.
741 // The hull information is passed as a large floating point array.
742 // The format is:
743 // convHulls[0] = number of hulls
744 // convHulls[1] = number of vertices in first hull
745 // convHulls[2] = hull centroid X coordinate
746 // convHulls[3] = hull centroid Y coordinate
747 // convHulls[4] = hull centroid Z coordinate
748 // convHulls[5] = first hull vertex X
749 // convHulls[6] = first hull vertex Y
750 // convHulls[7] = first hull vertex Z
751 // convHulls[8] = second hull vertex X
752 // ...
753 // convHulls[n] = number of vertices in second hull
754 // convHulls[n+1] = second hull centroid X coordinate
755 // ...
756 //
757 // TODO: is is very inefficient. Someday change the convex hull generator to return
758 // data structures that do not need to be converted in order to pass to Bullet.
759 // And maybe put the values directly into pinned memory rather than marshaling.
760 int hullCount = m_hulls.Count;
761 int totalVertices = 1; // include one for the count of the hulls
762 foreach (ConvexResult cr in m_hulls)
763 {
764 totalVertices += 4; // add four for the vertex count and centroid
765 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
766 }
767 float[] convHulls = new float[totalVertices];
768
769 convHulls[0] = (float)hullCount;
770 int jj = 1;
771 foreach (ConvexResult cr in m_hulls)
772 {
773 // copy vertices for index access
774 float3[] verts = new float3[cr.HullVertices.Count];
775 int kk = 0;
776 foreach (float3 ff in cr.HullVertices)
777 {
778 verts[kk++] = ff;
779 }
780
781 // add to the array one hull's worth of data
782 convHulls[jj++] = cr.HullIndices.Count;
783 convHulls[jj++] = 0f; // centroid x,y,z
784 convHulls[jj++] = 0f;
785 convHulls[jj++] = 0f;
786 foreach (int ind in cr.HullIndices)
787 {
788 convHulls[jj++] = verts[ind].x;
789 convHulls[jj++] = verts[ind].y;
790 convHulls[jj++] = verts[ind].z;
791 }
792 }
793 // create the hull data structure in Bullet
794 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
795 }
796 }
797
798 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
799 newShape.shapeKey = newHullKey;
800
801 return newShape;
802 }
803
804 // Callback from convex hull creater with a newly created hull.
805 // Just add it to our collection of hulls for this shape.
806 private void HullReturn(ConvexResult result)
807 {
808 m_hulls.Add(result);
809 return;
810 }
811
812 // Compound shapes are always built from scratch.
813 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
814 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
815 {
816 // Remove reference to the old shape
817 // Don't need to do this as the shape is freed when the new root shape is created below.
818 // DereferenceShape(prim.PhysShape, true, shapeCallback);
819
820 BulletShape cShape = new BulletShape(
821 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
822
823 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
824 CreateGeomMeshOrHull(prim, shapeCallback);
825 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
826 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
827 prim.LocalID, cShape, prim.PhysShape);
828
829 prim.PhysShape = cShape;
830
831 return true;
832 }
833
834 // Create a hash of all the shape parameters to be used as a key
835 // for this particular shape.
836 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
837 {
838 // level of detail based on size and type of the object
839 float lod = BSParam.MeshLOD;
840 if (pbs.SculptEntry)
841 lod = BSParam.SculptLOD;
842
843 // Mega prims usually get more detail because one can interact with shape approximations at this size.
844 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
845 if (maxAxis > BSParam.MeshMegaPrimThreshold)
846 lod = BSParam.MeshMegaPrimLOD;
847
848 retLod = lod;
849 return pbs.GetMeshKey(size, lod);
850 }
851 // For those who don't want the LOD
852 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
853 {
854 float lod;
855 return ComputeShapeKey(size, pbs, out lod);
856 }
857
858 // The creation of a mesh or hull can fail if an underlying asset is not available.
859 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
860 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
861 // The first case causes the asset to be fetched. The second case requires
862 // us to not loop forever.
863 // Called after creating a physical mesh or hull. If the physical shape was created,
864 // just return.
865 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
866 {
867 // If the shape was successfully created, nothing more to do
868 if (newShape.HasPhysicalShape)
869 return newShape;
870
871 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
872 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
873 {
874 prim.LastAssetBuildFailed = true;
875 BSPhysObject xprim = prim;
876 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
877 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
878 Util.FireAndForget(delegate
879 {
880 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
881 if (assetProvider != null)
882 {
883 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
884 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
885 {
886 if (!yprim.BaseShape.SculptEntry)
887 return;
888 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
889 return;
890
891 yprim.BaseShape.SculptData = asset.Data;
892 // This will cause the prim to see that the filler shape is not the right
893 // one and try again to build the object.
894 // No race condition with the normal shape setting since the rebuild is at taint time.
895 yprim.ForceBodyShapeRebuild(false);
896
897 });
898 }
899 });
900 }
901 else
902 {
903 if (prim.LastAssetBuildFailed)
904 {
905 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
906 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
907 }
908 }
909
910 // While we figure out the real problem, stick a simple native shape on the object.
911 BulletShape fillinShape =
912 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
913
914 return fillinShape;
915 }
916
917 // Create a body object in Bullet.
918 // Updates prim.BSBody with the information about the new body if one is created.
919 // Returns 'true' if an object was actually created.
920 // Called at taint-time.
921 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
922 BodyDestructionCallback bodyCallback)
923 {
924 bool ret = false;
925
926 // the mesh, hull or native shape must have already been created in Bullet
927 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
928
929 // If there is an existing body, verify it's of an acceptable type.
930 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
931 if (!mustRebuild)
932 {
933 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
934 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
935 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
936 {
937 // If the collisionObject is not the correct type for solidness, rebuild what's there
938 mustRebuild = true;
939 }
940 }
941
942 if (mustRebuild || forceRebuild)
943 {
944 // Free any old body
945 DereferenceBody(prim.PhysBody, true, bodyCallback);
946
947 BulletBody aBody;
948 Object bodyPtr = null;
949 if (prim.IsSolid)
950 {
951 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
952 prim.LocalID, prim.RawPosition, prim.RawOrientation);
953 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString());
954 }
955 else
956 {
957 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
958 prim.LocalID, prim.RawPosition, prim.RawOrientation);
959 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString());
960 }
961 aBody = new BulletBody(prim.LocalID, bodyPtr);
962
963 ReferenceBody(aBody, true);
964
965 prim.PhysBody = aBody;
966
967 ret = true;
968 }
969
970 return ret;
971 }
972
973 private bool TryGetMeshByPtr(Object addr, out MeshDesc outDesc)
974 {
975 bool ret = false;
976 MeshDesc foundDesc = new MeshDesc();
977 foreach (MeshDesc md in Meshes.Values)
978 {
979 if (md.ptr == addr)
980 {
981 foundDesc = md;
982 ret = true;
983 break;
984 }
985
986 }
987 outDesc = foundDesc;
988 return ret;
989 }
990
991 private bool TryGetHullByPtr(Object addr, out HullDesc outDesc)
992 {
993 bool ret = false;
994 HullDesc foundDesc = new HullDesc();
995 foreach (HullDesc hd in Hulls.Values)
996 {
997 if (hd.ptr == addr)
998 {
999 foundDesc = hd;
1000 ret = true;
1001 break;
1002 }
1003
1004 }
1005 outDesc = foundDesc;
1006 return ret;
1007 }
1008
1009 private void DetailLog(string msg, params Object[] args)
1010 {
1011 if (PhysicsScene.PhysicsLogging.Enabled)
1012 PhysicsScene.DetailLog(msg, args);
1013 }
1014}
1015}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs
new file mode 100644
index 0000000..8ff0275
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs
@@ -0,0 +1,208 @@
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 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35public abstract class BSShape
36{
37 public Object ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; }
42
43 public BSShape()
44 {
45 ptr = null;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now;
50 }
51
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 {
55 BSShape ret = null;
56
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 {
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73
74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76
77 return ret;
78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 {
81 return null;
82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 {
85 return null;
86 }
87
88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene);
90
91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference();
93
94 public override string ToString()
95 {
96 StringBuilder buff = new StringBuilder();
97 buff.Append("<p=");
98 buff.Append(ptr.ToString());
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c=");
104 buff.Append(referenceCount.ToString());
105 buff.Append(">");
106 return buff.ToString();
107 }
108}
109
110public class BSShapeNull : BSShape
111{
112 public BSShapeNull() : base()
113 {
114 }
115 public static BSShape GetReference() { return new BSShapeNull(); }
116 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
117}
118
119public class BSShapeNative : BSShape
120{
121 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
122 public BSShapeNative() : base()
123 {
124 }
125 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 {
128 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
130 }
131
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
133 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
134 {
135 ShapeData nativeShapeData = new ShapeData();
136 nativeShapeData.Type = shapeType;
137 nativeShapeData.ID = prim.LocalID;
138 nativeShapeData.Scale = prim.Scale;
139 nativeShapeData.Size = prim.Scale;
140 nativeShapeData.MeshKey = (ulong)shapeKey;
141 nativeShapeData.HullKey = (ulong)shapeKey;
142
143
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 }
149 else
150 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
152 }
153 if (ptr == null)
154 {
155 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
156 LogHeader, prim.LocalID, shapeType);
157 }
158 type = shapeType;
159 key = (UInt64)shapeKey;
160 }
161 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene)
163 {
164 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
167 ptr = null;
168 // Garbage collection will free up this instance.
169 }
170}
171
172public class BSShapeMesh : BSShape
173{
174 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
175 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
176
177 public BSShapeMesh() : base()
178 {
179 }
180 public static BSShape GetReference() { return new BSShapeNull(); }
181 public override void Dereference(BSScene physicsScene) { }
182}
183
184public class BSShapeHull : BSShape
185{
186 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
187 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
188
189 public BSShapeHull() : base()
190 {
191 }
192 public static BSShape GetReference() { return new BSShapeNull(); }
193 public override void Dereference(BSScene physicsScene) { }
194}
195
196public class BSShapeCompound : BSShape
197{
198 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
199 public BSShapeCompound() : base()
200 {
201 }
202 public static BSShape GetReference(BSPhysObject prim)
203 {
204 return new BSShapeNull();
205 }
206 public override void Dereference(BSScene physicsScene) { }
207}
208}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs
new file mode 100644
index 0000000..ba17059
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs
@@ -0,0 +1,175 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, null);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, null);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSParam.TerrainCollisionMargin);
97
98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
100 BSPhysicsShapeType.SHAPE_TERRAIN);
101
102 // The terrain object initial position is at the center of the object
103 Vector3 centerPos;
104 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f - 0.5f);
107
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111
112 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
117
118 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr, centerPos, Quaternion.Identity);
120
121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123
124 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 m_mapInfo.terrainBody.ApplyCollisionMask();
126
127 // Make it so the terrain will not move or be considered for movement.
128 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
129
130 return;
131 }
132
133 // If there is information in m_mapInfo pointing to physical structures, release same.
134 private void ReleaseHeightMapTerrain()
135 {
136 if (m_mapInfo != null)
137 {
138 if (m_mapInfo.terrainBody.HasPhysicalBody)
139 {
140 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
141 // Frees both the body and the shape.
142 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
143 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
144 }
145 }
146 m_mapInfo = null;
147 }
148
149 // The passed position is relative to the base of the region.
150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
151 {
152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
153
154 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
155 try
156 {
157 ret = m_mapInfo.heightMap[mapIndex];
158 }
159 catch
160 {
161 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
162 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
163 LogHeader, m_mapInfo.terrainRegionBase, pos);
164 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
165 }
166 return ret;
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 }
174}
175}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs
new file mode 100644
index 0000000..66d62f0
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs
@@ -0,0 +1,461 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 public BSScene PhysicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 PhysicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
67}
68
69// ==========================================================================================
70public sealed class BSTerrainManager : IDisposable
71{
72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
73
74 // These height values are fractional so the odd values will be
75 // noticable when debugging.
76 public const float HEIGHT_INITIALIZATION = 24.987f;
77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
80
81 // If the min and max height are equal, we reduce the min by this
82 // amount to make sure that a bounding box is built for the terrain.
83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
84
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);
87
88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; }
90
91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane;
93
94 // If doing mega-regions, if we're region zero we will be managing multiple
95 // region terrains since region zero does the physics for the whole mega-region.
96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
97
98 // Flags used to know when to recalculate the height.
99 private bool m_terrainModified = false;
100
101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
102 // This is incremented before assigning to new region so it is the last ID allocated.
103 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
104 public uint HighestTerrainID { get {return m_terrainCount; } }
105
106 // If doing mega-regions, this holds our offset from region zero of
107 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
108 private Vector3 m_worldOffset;
109 // If the parent region (region 0), this is the extent of the combined regions
110 // relative to the origin of region zero
111 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113
114 public BSTerrainManager(BSScene physicsScene)
115 {
116 PhysicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118
119 // Assume one region of default size
120 m_worldOffset = Vector3.Zero;
121 m_worldMax = new Vector3(DefaultRegionSize);
122 MegaRegionParentPhysicsScene = null;
123 }
124
125 public void Dispose()
126 {
127 ReleaseGroundPlaneAndTerrain();
128 }
129
130 // Create the initial instance of terrain and the underlying ground plane.
131 // This is called from the initialization routine so we presume it is
132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain()
134 {
135 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = new BulletShape(
137 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
138 BSParam.TerrainCollisionMargin),
139 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
140 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
141 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
142 Vector3.Zero, Quaternion.Identity));
143 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr, Vector3.Zero, Quaternion.Identity);
144 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
145 // Ground plane does not move
146 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
147 // Everything collides with the ground plane.
148 m_groundPlane.collisionType = CollisionType.Groundplane;
149 m_groundPlane.ApplyCollisionMask();
150
151 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
155
156 // Release all the terrain structures we might have allocated
157 public void ReleaseGroundPlaneAndTerrain()
158 {
159 if (m_groundPlane.HasPhysicalBody)
160 {
161 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
162 {
163 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
164 }
165 m_groundPlane.Clear();
166 }
167
168 ReleaseTerrain();
169 }
170
171 // Release all the terrain we have allocated
172 public void ReleaseTerrain()
173 {
174 lock (m_terrains)
175 {
176 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
177 {
178 kvp.Value.Dispose();
179 }
180 m_terrains.Clear();
181 }
182 }
183
184 // The simulator wants to set a new heightmap for the terrain.
185 public void SetTerrain(float[] heightMap) {
186 float[] localHeightMap = heightMap;
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()
190 {
191 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
192 {
193 // If a child of a mega-region, we shouldn't have any terrain allocated for us
194 ReleaseGroundPlaneAndTerrain();
195 // If doing the mega-prim stuff and we are the child of the zero region,
196 // the terrain is added to our parent
197 if (MegaRegionParentPhysicsScene is BSScene)
198 {
199 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
200 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
201 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
202 BSScene.CHILDTERRAIN_ID, localHeightMap,
203 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
204 }
205 }
206 else
207 {
208 // If not doing the mega-prim thing, just change the terrain
209 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
210
211 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
212 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
213 }
214 });
215 }
216
217 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
218 // based on the passed information. The 'id' should be either the terrain id or
219 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
220 // The latter feature is for creating child terrains for mega-regions.
221 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
222 // terrain shape is created and added to the body.
223 // This call is most often used to update the heightMap and parameters of the terrain.
224 // (The above does suggest that some simplification/refactoring is in order.)
225 // Called during taint-time.
226 private void UpdateTerrain(uint id, float[] heightMap,
227 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
228 {
229 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
230 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
231
232 // Find high and low points of passed heightmap.
233 // The min and max passed in is usually the area objects can be in (maximum
234 // object height, for instance). The terrain wants the bounding box for the
235 // terrain so replace passed min and max Z with the actual terrain min/max Z.
236 float minZ = float.MaxValue;
237 float maxZ = float.MinValue;
238 foreach (float height in heightMap)
239 {
240 if (height < minZ) minZ = height;
241 if (height > maxZ) maxZ = height;
242 }
243 if (minZ == maxZ)
244 {
245 // If min and max are the same, reduce min a little bit so a good bounding box is created.
246 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
247 }
248 minCoords.Z = minZ;
249 maxCoords.Z = maxZ;
250
251 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
252
253 lock (m_terrains)
254 {
255 BSTerrainPhys terrainPhys;
256 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
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
262 // Remove old terrain from the collection
263 m_terrains.Remove(terrainRegionBase);
264 // Release any physical memory it may be using.
265 terrainPhys.Dispose();
266
267 if (MegaRegionParentPhysicsScene == null)
268 {
269 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
270 m_terrains.Add(terrainRegionBase, newTerrainPhys);
271
272 m_terrainModified = true;
273 }
274 else
275 {
276 // It's possible that Combine() was called after this code was queued.
277 // If we are a child of combined regions, we don't create any terrain for us.
278 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
279
280 // Get rid of any terrain that may have been allocated for us.
281 ReleaseGroundPlaneAndTerrain();
282
283 // I hate doing this, but just bail
284 return;
285 }
286 }
287 else
288 {
289 // 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
291
292 // if this is a child terrain, calculate a unique terrain id
293 uint newTerrainID = id;
294 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
295 newTerrainID = ++m_terrainCount;
296
297 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
298 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
299 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
300 m_terrains.Add(terrainRegionBase, newTerrainPhys);
301
302 m_terrainModified = true;
303 }
304 }
305 }
306
307 // TODO: redo terrain implementation selection to allow other base types than heightMap.
308 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
309 {
310 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
311 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
312 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
313 BSTerrainPhys newTerrainPhys = null;
314 switch ((int)BSParam.TerrainImplementation)
315 {
316 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
317 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
318 heightMap, minCoords, maxCoords);
319 break;
320 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
321 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
322 heightMap, minCoords, maxCoords);
323 break;
324 default:
325 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
326 LogHeader,
327 (int)BSParam.TerrainImplementation,
328 BSParam.TerrainImplementation,
329 PhysicsScene.RegionName, terrainRegionBase);
330 break;
331 }
332 return newTerrainPhys;
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 }
342
343 // Given an X and Y, find the height of the terrain.
344 // Since we could be handling multiple terrains for a mega-region,
345 // the base of the region is calcuated assuming all regions are
346 // the same size and that is the default.
347 // Once the heightMapInfo is found, we have all the information to
348 // compute the offset into the array.
349 private float lastHeightTX = 999999f;
350 private float lastHeightTY = 999999f;
351 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
352 public float GetTerrainHeightAtXYZ(Vector3 pos)
353 {
354 float tX = pos.X;
355 float tY = pos.Y;
356 // You'd be surprized at the number of times this routine is called
357 // with the same parameters as last time.
358 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
359 return lastHeight;
360 m_terrainModified = false;
361
362 lastHeightTX = tX;
363 lastHeightTY = tY;
364 float ret = HEIGHT_GETHEIGHT_RET;
365
366 Vector3 terrainBaseXYZ;
367 BSTerrainPhys physTerrain;
368 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
369 {
370 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
371 }
372 else
373 {
374 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
375 LogHeader, PhysicsScene.RegionName, tX, tY);
376 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
377 BSScene.DetailLogZero, pos, terrainBaseXYZ);
378 }
379
380 lastHeight = ret;
381 return ret;
382 }
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
420 // Although no one seems to check this, I do support combining.
421 public bool SupportsCombining()
422 {
423 return true;
424 }
425
426 // This routine is called two ways:
427 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
428 // extent of the combined regions. This is to inform the parent of the size
429 // of the combined regions.
430 // and one with 'offset' as the offset of the child region to the base region,
431 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
432 // child of its relative base and new parent.
433 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
434 {
435 m_worldOffset = offset;
436 m_worldMax = extents;
437 MegaRegionParentPhysicsScene = pScene;
438 if (pScene != null)
439 {
440 // We are a child.
441 // We want m_worldMax to be the highest coordinate of our piece of terrain.
442 m_worldMax = offset + DefaultRegionSize;
443 }
444 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
445 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
446 }
447
448 // Unhook all the combining that I know about.
449 public void UnCombine(PhysicsScene pScene)
450 {
451 // Just like ODE, we don't do anything yet.
452 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
453 }
454
455
456 private void DetailLog(string msg, params Object[] args)
457 {
458 PhysicsScene.PhysicsLogging.Write(msg, args);
459 }
460}
461}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs
new file mode 100644
index 0000000..6083dd4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs
@@ -0,0 +1,267 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
93
94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
95 indicesCount, indices, verticesCount, vertices),
96 BSPhysicsShapeType.SHAPE_MESH);
97 if (!m_terrainShape.HasPhysicalShape)
98 {
99 // DISASTER!!
100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
101 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 Vector3 pos = regionBase;
107 Quaternion rot = Quaternion.Identity;
108
109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
110 if (!m_terrainBody.HasPhysicalBody)
111 {
112 // DISASTER!!
113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
114 // Something is very messed up and a crash is in our future.
115 return;
116 }
117
118 // Set current terrain attributes
119 BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction);
120 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction);
121 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution);
122 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
123
124 // Static objects are not very massive.
125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
126
127 // Put the new terrain to the world of physical objects
128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr, pos, rot);
129
130 // Redo its bounding box now that it is in the world
131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
132
133 m_terrainBody.collisionType = CollisionType.Terrain;
134 m_terrainBody.ApplyCollisionMask();
135
136 // Make it so the terrain will not move or be considered for movement.
137 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
138 }
139
140 public override void Dispose()
141 {
142 if (m_terrainBody.HasPhysicalBody)
143 {
144 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
145 // Frees both the body and the shape.
146 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
147 }
148 }
149
150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
151 {
152 // For the moment use the saved heightmap to get the terrain height.
153 // TODO: raycast downward to find the true terrain below the position.
154 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
155
156 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
157 try
158 {
159 ret = m_savedHeightMap[mapIndex];
160 }
161 catch
162 {
163 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
164 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
165 LogHeader, TerrainBase, pos);
166 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
167 }
168 return ret;
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
177 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
178 // Return 'true' if successfully created.
179 public static bool ConvertHeightmapToMesh(
180 BSScene physicsScene,
181 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
182 float extentX, float extentY, // zero based range for output vertices
183 Vector3 extentBase, // base to be added to all vertices
184 float magnification, // number of vertices to create between heightMap coords
185 out int indicesCountO, out int[] indicesO,
186 out int verticesCountO, out float[] verticesO)
187 {
188 bool ret = false;
189
190 int indicesCount = 0;
191 int verticesCount = 0;
192 int[] indices = new int[0];
193 float[] vertices = new float[0];
194
195 // Simple mesh creation which assumes magnification == 1.
196 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
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.
203 try
204 {
205 // One vertice per heightmap value plus the vertices off the top and bottom edge.
206 int totalVertices = (sizeX + 1) * (sizeY + 1);
207 vertices = new float[totalVertices * 3];
208 int totalIndices = sizeX * sizeY * 6;
209 indices = new int[totalIndices];
210
211 float magX = (float)sizeX / extentX;
212 float magY = (float)sizeY / extentY;
213 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
214 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
215 float minHeight = float.MaxValue;
216 // Note that sizeX+1 vertices are created since there is land between this and the next region.
217 for (int yy = 0; yy <= sizeY; yy++)
218 {
219 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
220 {
221 int offset = yy * sizeX + xx;
222 // Extend the height with the height from the last row or column
223 if (yy == sizeY) offset -= sizeX;
224 if (xx == sizeX) offset -= 1;
225 float height = heightMap[offset];
226 minHeight = Math.Min(minHeight, height);
227 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
228 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
229 vertices[verticesCount + 2] = height + extentBase.Z;
230 verticesCount += 3;
231 }
232 }
233 verticesCount = verticesCount / 3;
234
235 for (int yy = 0; yy < sizeY; yy++)
236 {
237 for (int xx = 0; xx < sizeX; xx++)
238 {
239 int offset = yy * (sizeX + 1) + xx;
240 // Each vertices is presumed to be the upper left corner of a box of two triangles
241 indices[indicesCount + 0] = offset;
242 indices[indicesCount + 1] = offset + 1;
243 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
244 indices[indicesCount + 3] = offset + 1;
245 indices[indicesCount + 4] = offset + sizeX + 2;
246 indices[indicesCount + 5] = offset + sizeX + 1;
247 indicesCount += 6;
248 }
249 }
250
251 ret = true;
252 }
253 catch (Exception e)
254 {
255 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
256 LogHeader, physicsScene.RegionName, extentBase, e);
257 }
258
259 indicesCountO = indicesCount;
260 indicesO = indices;
261 verticesCountO = verticesCount;
262 verticesO = vertices;
263
264 return ret;
265 }
266}
267}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs
new file mode 100644
index 0000000..93643c9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs
@@ -0,0 +1,1603 @@
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.IO;
30using System.Runtime.InteropServices;
31using System.Security;
32using System.Text;
33using BulletXNA;
34using OpenMetaverse;
35using BulletXNA.LinearMath;
36using BulletXNA.BulletCollision;
37using BulletXNA.BulletDynamics;
38using BulletXNA.BulletCollision.CollisionDispatch;
39using OpenSim.Framework;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin {
42
43// Classes to allow some type checking for the API
44// These hold pointers to allocated objects in the unmanaged space.
45
46
47
48 // Constraint type values as defined by Bullet
49public enum ConstraintType : int
50{
51 POINT2POINT_CONSTRAINT_TYPE = 3,
52 HINGE_CONSTRAINT_TYPE,
53 CONETWIST_CONSTRAINT_TYPE,
54 D6_CONSTRAINT_TYPE,
55 SLIDER_CONSTRAINT_TYPE,
56 CONTACT_CONSTRAINT_TYPE,
57 D6_SPRING_CONSTRAINT_TYPE,
58 MAX_CONSTRAINT_TYPE
59}
60
61// ===============================================================================
62[StructLayout(LayoutKind.Sequential)]
63public struct ConvexHull
64{
65 Vector3 Offset;
66 int VertexCount;
67 Vector3[] Vertices;
68}
69public enum BSPhysicsShapeType
70{
71 SHAPE_UNKNOWN = 0,
72 SHAPE_CAPSULE = 1,
73 SHAPE_BOX = 2,
74 SHAPE_CONE = 3,
75 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6,
78 SHAPE_HULL = 7,
79 // following defined by BulletSim
80 SHAPE_GROUNDPLANE = 20,
81 SHAPE_TERRAIN = 21,
82 SHAPE_COMPOUND = 22,
83 SHAPE_HEIGHTMAP = 23,
84};
85
86// The native shapes have predefined shape hash keys
87public enum FixedShapeKey : ulong
88{
89 KEY_NONE = 0,
90 KEY_BOX = 1,
91 KEY_SPHERE = 2,
92 KEY_CONE = 3,
93 KEY_CYLINDER = 4,
94 KEY_CAPSULE = 5,
95}
96
97[StructLayout(LayoutKind.Sequential)]
98public struct ShapeData
99{
100 public uint ID;
101 public BSPhysicsShapeType Type;
102 public Vector3 Position;
103 public Quaternion Rotation;
104 public Vector3 Velocity;
105 public Vector3 Scale;
106 public float Mass;
107 public float Buoyancy;
108 public System.UInt64 HullKey;
109 public System.UInt64 MeshKey;
110 public float Friction;
111 public float Restitution;
112 public float Collidable; // true of things bump into this
113 public float Static; // true if a static object. Otherwise gravity, etc.
114 public float Solid; // true if object cannot be passed through
115 public Vector3 Size;
116
117 // note that bools are passed as floats since bool size changes by language and architecture
118 public const float numericTrue = 1f;
119 public const float numericFalse = 0f;
120}
121[StructLayout(LayoutKind.Sequential)]
122public struct SweepHit
123{
124 public uint ID;
125 public float Fraction;
126 public Vector3 Normal;
127 public Vector3 Point;
128}
129[StructLayout(LayoutKind.Sequential)]
130public struct RaycastHit
131{
132 public uint ID;
133 public float Fraction;
134 public Vector3 Normal;
135}
136[StructLayout(LayoutKind.Sequential)]
137public struct CollisionDesc
138{
139 public uint aID;
140 public uint bID;
141 public Vector3 point;
142 public Vector3 normal;
143}
144[StructLayout(LayoutKind.Sequential)]
145public struct EntityProperties
146{
147 public uint ID;
148 public Vector3 Position;
149 public Quaternion Rotation;
150 public Vector3 Velocity;
151 public Vector3 Acceleration;
152 public Vector3 RotationalVelocity;
153 public override string ToString()
154 {
155 return string.Format("ID:{0}, Pos:<{1:F},{2:F},{3:F}>, Rot:<{4:F},{5:F},{6:F},{7:F}>, LVel:<{8:F},{9:F},{10:F}>, AVel:<{11:F},{12:F},{13:F}>",
156 ID.ToString(),
157 Position.X,Position.Y,Position.Z,
158 Rotation.X,Rotation.Y,Rotation.Z,Rotation.W,
159 Velocity.X,Velocity.Y,Velocity.Z,
160 RotationalVelocity.X,RotationalVelocity.Y,RotationalVelocity.Z
161 );
162 }
163}
164
165// Format of this structure must match the definition in the C++ code
166// NOTE: adding the X causes compile breaks if used. These are unused symbols
167// that can be removed from both here and the unmanaged definition of this structure.
168[StructLayout(LayoutKind.Sequential)]
169public struct ConfigurationParameters
170{
171 public float defaultFriction;
172 public float defaultDensity;
173 public float defaultRestitution;
174 public float collisionMargin;
175 public float gravity;
176
177 public float XlinearDamping;
178 public float XangularDamping;
179 public float XdeactivationTime;
180 public float XlinearSleepingThreshold;
181 public float XangularSleepingThreshold;
182 public float XccdMotionThreshold;
183 public float XccdSweptSphereRadius;
184 public float XcontactProcessingThreshold;
185
186 public float XterrainImplementation;
187 public float XterrainFriction;
188 public float XterrainHitFraction;
189 public float XterrainRestitution;
190 public float XterrainCollisionMargin;
191
192 public float XavatarFriction;
193 public float XavatarStandingFriction;
194 public float XavatarDensity;
195 public float XavatarRestitution;
196 public float XavatarCapsuleWidth;
197 public float XavatarCapsuleDepth;
198 public float XavatarCapsuleHeight;
199 public float XavatarContactProcessingThreshold;
200
201 public float XvehicleAngularDamping;
202
203 public float maxPersistantManifoldPoolSize;
204 public float maxCollisionAlgorithmPoolSize;
205 public float shouldDisableContactPoolDynamicAllocation;
206 public float shouldForceUpdateAllAabbs;
207 public float shouldRandomizeSolverOrder;
208 public float shouldSplitSimulationIslands;
209 public float shouldEnableFrictionCaching;
210 public float numberOfSolverIterations;
211
212 public float XlinksetImplementation;
213 public float XlinkConstraintUseFrameOffset;
214 public float XlinkConstraintEnableTransMotor;
215 public float XlinkConstraintTransMotorMaxVel;
216 public float XlinkConstraintTransMotorMaxForce;
217 public float XlinkConstraintERP;
218 public float XlinkConstraintCFM;
219 public float XlinkConstraintSolverIterations;
220
221 public float physicsLoggingFrames;
222
223 public const float numericTrue = 1f;
224 public const float numericFalse = 0f;
225}
226
227
228// The states a bullet collision object can have
229
230public enum ActivationState : uint
231{
232 UNDEFINED = 0,
233 ACTIVE_TAG = 1,
234 ISLAND_SLEEPING = 2,
235 WANTS_DEACTIVATION = 3,
236 DISABLE_DEACTIVATION = 4,
237 DISABLE_SIMULATION = 5,
238}
239
240public enum CollisionObjectTypes : int
241{
242 CO_COLLISION_OBJECT = 1 << 0,
243 CO_RIGID_BODY = 1 << 1,
244 CO_GHOST_OBJECT = 1 << 2,
245 CO_SOFT_BODY = 1 << 3,
246 CO_HF_FLUID = 1 << 4,
247 CO_USER_TYPE = 1 << 5,
248}
249
250// Values used by Bullet and BulletSim to control object properties.
251// Bullet's "CollisionFlags" has more to do with operations on the
252// object (if collisions happen, if gravity effects it, ...).
253 [Flags]
254public enum CollisionFlags : uint
255{
256 CF_STATIC_OBJECT = 1 << 0,
257 CF_KINEMATIC_OBJECT = 1 << 1,
258 CF_NO_CONTACT_RESPONSE = 1 << 2,
259 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
260 CF_CHARACTER_OBJECT = 1 << 4,
261 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
262 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
263 // Following used by BulletSim to control collisions and updates
264 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
265 BS_FLOATS_ON_WATER = 1 << 11,
266 BS_VEHICLE_COLLISIONS = 1 << 12,
267 BS_NONE = 0,
268 BS_ALL = 0xFFFFFFFF,
269
270 // These are the collision flags switched depending on physical state.
271 // The other flags are used for other things and should not be fooled with.
272 BS_ACTIVE = CF_STATIC_OBJECT
273 | CF_KINEMATIC_OBJECT
274 | CF_NO_CONTACT_RESPONSE
275};
276
277// Values for collisions groups and masks
278public enum CollisionFilterGroups : uint
279{
280 // Don't use the bit definitions!! Define the use in a
281 // filter/mask definition below. This way collision interactions
282 // are more easily debugged.
283 BNoneGroup = 0,
284 BDefaultGroup = 1 << 0,
285 BStaticGroup = 1 << 1,
286 BKinematicGroup = 1 << 2,
287 BDebrisGroup = 1 << 3,
288 BSensorTrigger = 1 << 4,
289 BCharacterGroup = 1 << 5,
290 BAllGroup = 0xFFFFFFFF,
291 // Filter groups defined by BulletSim
292 BGroundPlaneGroup = 1 << 10,
293 BTerrainGroup = 1 << 11,
294 BRaycastGroup = 1 << 12,
295 BSolidGroup = 1 << 13,
296 // BLinksetGroup = xx // a linkset proper is either static or dynamic
297 BLinksetChildGroup = 1 << 14,
298 // The collsion filters and masked are defined in one place -- don't want them scattered
299 AvatarGroup = BCharacterGroup,
300 AvatarMask = BAllGroup,
301 ObjectGroup = BSolidGroup,
302 ObjectMask = BAllGroup,
303 StaticObjectGroup = BStaticGroup,
304 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
305 LinksetGroup = BLinksetChildGroup,
306 LinksetMask = BAllGroup & ~BLinksetChildGroup, // linkset objects don't collide with each other
307 VolumeDetectGroup = BSensorTrigger,
308 VolumeDetectMask = ~BSensorTrigger,
309 TerrainGroup = BTerrainGroup,
310 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
311 GroundPlaneGroup = BGroundPlaneGroup,
312 GroundPlaneMask = BAllGroup
313
314};
315
316// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
317// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
318public enum ConstraintParams : int
319{
320 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
321 BT_CONSTRAINT_STOP_ERP,
322 BT_CONSTRAINT_CFM,
323 BT_CONSTRAINT_STOP_CFM,
324};
325public enum ConstraintParamAxis : int
326{
327 AXIS_LINEAR_X = 0,
328 AXIS_LINEAR_Y,
329 AXIS_LINEAR_Z,
330 AXIS_ANGULAR_X,
331 AXIS_ANGULAR_Y,
332 AXIS_ANGULAR_Z,
333 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
334 AXIS_ANGULAR_ALL,
335 AXIS_ALL
336};
337
338// ===============================================================================
339static class BulletSimAPI {
340 private static int m_collisionsThisFrame;
341 public delegate void DebugLogCallback(string msg);
342 /// <summary>
343 ///
344 /// </summary>
345 /// <param name="p"></param>
346 /// <param name="p_2"></param>
347 internal static bool RemoveObjectFromWorld2(object pWorld, object pBody)
348 {
349 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
350 RigidBody body = pBody as RigidBody;
351 world.RemoveRigidBody(body);
352 return true;
353 }
354
355 internal static void SetRestitution2(object pBody, float pRestitution)
356 {
357 RigidBody body = pBody as RigidBody;
358 body.SetRestitution(pRestitution);
359 }
360
361 internal static void SetMargin2(object pShape, float pMargin)
362 {
363 CollisionShape shape = pShape as CollisionShape;
364 shape.SetMargin(pMargin);
365 }
366
367 internal static void SetLocalScaling2(object pShape, Vector3 pScale)
368 {
369 CollisionShape shape = pShape as CollisionShape;
370 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
371 shape.SetLocalScaling(ref vec);
372
373 }
374
375 internal static void SetContactProcessingThreshold2(object pBody, float contactprocessingthreshold)
376 {
377 RigidBody body = pBody as RigidBody;
378 body.SetContactProcessingThreshold(contactprocessingthreshold);
379 }
380
381 internal static void SetCcdMotionThreshold2(object pBody, float pccdMotionThreashold)
382 {
383 RigidBody body = pBody as RigidBody;
384 body.SetCcdMotionThreshold(pccdMotionThreashold);
385 }
386
387 internal static void SetCcdSweptSphereRadius2(object pBody, float pCcdSweptSphereRadius)
388 {
389 RigidBody body = pBody as RigidBody;
390 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
391 }
392
393 internal static void SetAngularFactorV2(object pBody, Vector3 pAngularFactor)
394 {
395 RigidBody body = pBody as RigidBody;
396 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
397 }
398
399 internal static CollisionFlags AddToCollisionFlags2(object pBody, CollisionFlags pcollisionFlags)
400 {
401 CollisionObject body = pBody as CollisionObject;
402 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
403 existingcollisionFlags |= pcollisionFlags;
404 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
405 return (CollisionFlags) (uint) existingcollisionFlags;
406 }
407
408 internal static void AddObjectToWorld2(object pWorld, object pBody)
409 {
410 RigidBody body = pBody as RigidBody;
411 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
412 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
413
414 world.AddRigidBody(body);
415
416 //if (body.GetBroadphaseHandle() != null)
417 // world.UpdateSingleAabb(body);
418 }
419
420 internal static void AddObjectToWorld2(object pWorld, object pBody, Vector3 _position, Quaternion _orientation)
421 {
422 RigidBody body = pBody as RigidBody;
423 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
424 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
425
426 world.AddRigidBody(body);
427 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
428 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
429 _orientation.W);
430 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
431 mat._origin = vposition;
432 body.SetWorldTransform(mat);
433 //if (body.GetBroadphaseHandle() != null)
434 // world.UpdateSingleAabb(body);
435 }
436
437 internal static void ForceActivationState2(object pBody, ActivationState pActivationState)
438 {
439 CollisionObject body = pBody as CollisionObject;
440 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
441 }
442
443 internal static void UpdateSingleAabb2(object pWorld, object pBody)
444 {
445 CollisionObject body = pBody as CollisionObject;
446 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
447 world.UpdateSingleAabb(body);
448 }
449
450 internal static bool SetCollisionGroupMask2(object pBody, uint pGroup, uint pMask)
451 {
452 RigidBody body = pBody as RigidBody;
453 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
454 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
455 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
456 return false;
457 return true;
458 }
459
460 internal static void ClearAllForces2(object pBody)
461 {
462 CollisionObject body = pBody as CollisionObject;
463 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
464 body.SetInterpolationLinearVelocity(ref zeroVector);
465 body.SetInterpolationAngularVelocity(ref zeroVector);
466 IndexedMatrix bodytransform = body.GetWorldTransform();
467
468 body.SetInterpolationWorldTransform(ref bodytransform);
469
470 if (body is RigidBody)
471 {
472 RigidBody rigidbody = body as RigidBody;
473 rigidbody.SetLinearVelocity(zeroVector);
474 rigidbody.SetAngularVelocity(zeroVector);
475 rigidbody.ClearForces();
476 }
477 }
478
479 internal static void SetInterpolationAngularVelocity2(object pBody, Vector3 pVector3)
480 {
481 RigidBody body = pBody as RigidBody;
482 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
483 body.SetInterpolationAngularVelocity(ref vec);
484 }
485
486 internal static void SetAngularVelocity2(object pBody, Vector3 pVector3)
487 {
488 RigidBody body = pBody as RigidBody;
489 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
490 body.SetAngularVelocity(ref vec);
491 }
492
493 internal static void ClearForces2(object pBody)
494 {
495 RigidBody body = pBody as RigidBody;
496 body.ClearForces();
497 }
498
499 internal static void SetTranslation2(object pBody, Vector3 _position, Quaternion _orientation)
500 {
501 RigidBody body = pBody as RigidBody;
502 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
503 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
504 _orientation.W);
505 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
506 mat._origin = vposition;
507 body.SetWorldTransform(mat);
508
509 }
510
511 internal static Vector3 GetPosition2(object pBody)
512 {
513 RigidBody body = pBody as RigidBody;
514 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
515 return new Vector3(pos.X, pos.Y, pos.Z);
516 }
517
518 internal static Vector3 CalculateLocalInertia2(object pShape, float pphysMass)
519 {
520 CollisionShape shape = pShape as CollisionShape;
521 IndexedVector3 inertia = IndexedVector3.Zero;
522 shape.CalculateLocalInertia(pphysMass, out inertia);
523 return new Vector3(inertia.X, inertia.Y, inertia.Z);
524 }
525
526 internal static void SetMassProps2(object pBody, float pphysMass, Vector3 plocalInertia)
527 {
528 RigidBody body = pBody as RigidBody;
529 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
530 body.SetMassProps(pphysMass, inertia);
531 }
532
533
534 internal static void SetObjectForce2(object pBody, Vector3 _force)
535 {
536 RigidBody body = pBody as RigidBody;
537 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
538 body.SetTotalForce(ref force);
539 }
540
541 internal static void SetFriction2(object pBody, float _currentFriction)
542 {
543 RigidBody body = pBody as RigidBody;
544 body.SetFriction(_currentFriction);
545 }
546
547 internal static void SetLinearVelocity2(object pBody, Vector3 _velocity)
548 {
549 RigidBody body = pBody as RigidBody;
550 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
551 body.SetLinearVelocity(velocity);
552 }
553
554 internal static void Activate2(object pBody, bool pforceactivation)
555 {
556 RigidBody body = pBody as RigidBody;
557 body.Activate(pforceactivation);
558
559 }
560
561 internal static Quaternion GetOrientation2(object pBody)
562 {
563 RigidBody body = pBody as RigidBody;
564 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
565 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
566 }
567
568 internal static CollisionFlags RemoveFromCollisionFlags2(object pBody, CollisionFlags pcollisionFlags)
569 {
570 RigidBody body = pBody as RigidBody;
571 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
572 existingcollisionFlags &= ~pcollisionFlags;
573 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
574 return (CollisionFlags)(uint)existingcollisionFlags;
575 }
576
577 internal static void SetGravity2(object pBody, Vector3 pGravity)
578 {
579 RigidBody body = pBody as RigidBody;
580 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
581 body.SetGravity(gravity);
582 }
583
584 internal static bool DestroyConstraint2(object pBody, object pConstraint)
585 {
586 RigidBody body = pBody as RigidBody;
587 TypedConstraint constraint = pConstraint as TypedConstraint;
588 body.RemoveConstraintRef(constraint);
589 return true;
590 }
591
592 internal static bool SetLinearLimits2(object pConstraint, Vector3 low, Vector3 high)
593 {
594 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
595 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
596 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
597 constraint.SetLinearLowerLimit(lowlimit);
598 constraint.SetLinearUpperLimit(highlimit);
599 return true;
600 }
601
602 internal static bool SetAngularLimits2(object pConstraint, Vector3 low, Vector3 high)
603 {
604 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
605 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
606 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
607 constraint.SetAngularLowerLimit(lowlimit);
608 constraint.SetAngularUpperLimit(highlimit);
609 return true;
610 }
611
612 internal static void SetConstraintNumSolverIterations2(object pConstraint, float cnt)
613 {
614 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
615 constraint.SetOverrideNumSolverIterations((int)cnt);
616 }
617
618 internal static void CalculateTransforms2(object pConstraint)
619 {
620 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
621 constraint.CalculateTransforms();
622 }
623
624 internal static void SetConstraintEnable2(object pConstraint, float p_2)
625 {
626 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
627 constraint.SetEnabled((p_2 == 0) ? false : true);
628 }
629
630
631 //BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
632 internal static object Create6DofConstraint2(object pWorld, object pBody1, object pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
633
634 {
635 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
636 RigidBody body1 = pBody1 as RigidBody;
637 RigidBody body2 = pBody2 as RigidBody;
638 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
639 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
640 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
641 frame1._origin = frame1v;
642
643 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
644 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
645 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
646 frame2._origin = frame1v;
647
648 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
649 puseLinearReferenceFrameA);
650 consttr.CalculateTransforms();
651 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
652
653 return consttr;
654 }
655
656
657 /// <summary>
658 ///
659 /// </summary>
660 /// <param name="pWorld"></param>
661 /// <param name="pBody1"></param>
662 /// <param name="pBody2"></param>
663 /// <param name="pjoinPoint"></param>
664 /// <param name="puseLinearReferenceFrameA"></param>
665 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
666 /// <returns></returns>
667 internal static object Create6DofConstraintToPoint2(object pWorld, object pBody1, object pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
668 {
669 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
670 RigidBody body1 = pBody1 as RigidBody;
671 RigidBody body2 = pBody2 as RigidBody;
672 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
673 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
674
675 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
676 IndexedMatrix mat = IndexedMatrix.Identity;
677 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
678 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
679 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
680
681 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
682 consttr.CalculateTransforms();
683 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
684
685 return consttr;
686 }
687 //SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
688 internal static void SetFrames2(object pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
689 {
690 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
691 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
692 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
693 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
694 frame1._origin = frame1v;
695
696 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
697 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
698 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
699 frame2._origin = frame1v;
700 constraint.SetFrames(ref frame1, ref frame2);
701 }
702
703
704
705
706 internal static bool IsInWorld2(object pWorld, object pShapeObj)
707 {
708 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
709 CollisionObject shape = pShapeObj as CollisionObject;
710 return world.IsInWorld(shape);
711 }
712
713 internal static void SetInterpolationLinearVelocity2(object pBody, Vector3 VehicleVelocity)
714 {
715 RigidBody body = pBody as RigidBody;
716 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
717 body.SetInterpolationLinearVelocity(ref velocity);
718 }
719
720 internal static bool UseFrameOffset2(object pConstraint, float onOff)
721 {
722 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
723 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
724 return true;
725 }
726 //SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
727 internal static bool SetBreakingImpulseThreshold2(object pConstraint, float threshold)
728 {
729 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
730 constraint.SetBreakingImpulseThreshold(threshold);
731 return true;
732 }
733 //BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
734 internal static void SetAngularDamping2(object pBody, float angularDamping)
735 {
736 RigidBody body = pBody as RigidBody;
737 float lineardamping = body.GetLinearDamping();
738 body.SetDamping(lineardamping, angularDamping);
739
740 }
741
742 internal static void UpdateInertiaTensor2(object pBody)
743 {
744 RigidBody body = pBody as RigidBody;
745 body.UpdateInertiaTensor();
746 }
747
748 internal static void RecalculateCompoundShapeLocalAabb2( object pCompoundShape)
749 {
750
751 CompoundShape shape = pCompoundShape as CompoundShape;
752 shape.RecalculateLocalAabb();
753 }
754
755 //BulletSimAPI.GetCollisionFlags2(PhysBody.ptr)
756 internal static CollisionFlags GetCollisionFlags2(object pBody)
757 {
758 RigidBody body = pBody as RigidBody;
759 uint flags = (uint)body.GetCollisionFlags();
760 return (CollisionFlags) flags;
761 }
762
763 internal static void SetDamping2(object pBody, float pLinear, float pAngular)
764 {
765 RigidBody body = pBody as RigidBody;
766 body.SetDamping(pLinear, pAngular);
767 }
768 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
769 internal static void SetDeactivationTime2(object pBody, float pDeactivationTime)
770 {
771 RigidBody body = pBody as RigidBody;
772 body.SetDeactivationTime(pDeactivationTime);
773 }
774 //SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
775 internal static void SetSleepingThresholds2(object pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
776 {
777 RigidBody body = pBody as RigidBody;
778 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
779 }
780
781 internal static CollisionObjectTypes GetBodyType2(object pBody)
782 {
783 RigidBody body = pBody as RigidBody;
784 return (CollisionObjectTypes)(int) body.GetInternalType();
785 }
786
787 //BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
788 internal static void ApplyCentralForce2(object pBody, Vector3 pfSum)
789 {
790 RigidBody body = pBody as RigidBody;
791 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
792 body.ApplyCentralForce(ref fSum);
793 }
794 internal static void ApplyCentralImpulse2(object pBody, Vector3 pfSum)
795 {
796 RigidBody body = pBody as RigidBody;
797 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
798 body.ApplyCentralImpulse(ref fSum);
799 }
800 internal static void ApplyTorque2(object pBody, Vector3 pfSum)
801 {
802 RigidBody body = pBody as RigidBody;
803 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
804 body.ApplyTorque(ref fSum);
805 }
806 internal static void ApplyTorqueImpulse2(object pBody, Vector3 pfSum)
807 {
808 RigidBody body = pBody as RigidBody;
809 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
810 body.ApplyTorqueImpulse(ref fSum);
811 }
812
813 internal static void DumpRigidBody2(object p, object p_2)
814 {
815 //TODO:
816 }
817
818 internal static void DumpCollisionShape2(object p, object p_2)
819 {
820 //TODO:
821 }
822
823 internal static void DestroyObject2(object p, object p_2)
824 {
825 //TODO:
826 }
827
828 internal static void Shutdown2(object pWorld)
829 {
830 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
831 world.Cleanup();
832 }
833
834 internal static void DeleteCollisionShape2(object p, object p_2)
835 {
836 //TODO:
837 }
838 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
839
840 internal static object CreateBodyFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
841 {
842 CollisionWorld world = pWorld as CollisionWorld;
843 IndexedMatrix mat =
844 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
845 pRawOrientation.Z, pRawOrientation.W));
846 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
847 CollisionShape shape = pShape as CollisionShape;
848 //UpdateSingleAabb2(world, shape);
849 // TODO: Feed Update array into null
850 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
851
852 body.SetUserPointer(pLocalID);
853 return body;
854 }
855
856
857 internal static object CreateBodyWithDefaultMotionState2( object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
858 {
859
860 IndexedMatrix mat =
861 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
862 pRawOrientation.Z, pRawOrientation.W));
863 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
864
865 CollisionShape shape = pShape as CollisionShape;
866
867 // TODO: Feed Update array into null
868 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
869 body.SetWorldTransform(mat);
870 body.SetUserPointer(pLocalID);
871 return body;
872 }
873 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
874 internal static void SetCollisionFlags2(object pBody, CollisionFlags collisionFlags)
875 {
876 RigidBody body = pBody as RigidBody;
877 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
878 }
879 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
880 internal static void SetHitFraction2(object pBody, float pHitFraction)
881 {
882 RigidBody body = pBody as RigidBody;
883 body.SetHitFraction(pHitFraction);
884 }
885 //BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
886 internal static object BuildCapsuleShape2(object pWorld, float pRadius, float pHeight, Vector3 pScale)
887 {
888 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
889 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
890 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
891 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
892 capsuleShapeZ.SetLocalScaling(ref scale);
893
894 return capsuleShapeZ;
895 }
896
897 public static object Initialize2(Vector3 worldExtent, ConfigurationParameters[] o, int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, object mDebugLogCallbackHandle)
898 {
899 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
900
901 p.angularDamping = o[0].XangularDamping;
902 p.defaultFriction = o[0].defaultFriction;
903 p.defaultFriction = o[0].defaultFriction;
904 p.defaultDensity = o[0].defaultDensity;
905 p.defaultRestitution = o[0].defaultRestitution;
906 p.collisionMargin = o[0].collisionMargin;
907 p.gravity = o[0].gravity;
908
909 p.linearDamping = o[0].XlinearDamping;
910 p.angularDamping = o[0].XangularDamping;
911 p.deactivationTime = o[0].XdeactivationTime;
912 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
913 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
914 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
915 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
916 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
917
918 p.terrainImplementation = o[0].XterrainImplementation;
919 p.terrainFriction = o[0].XterrainFriction;
920
921 p.terrainHitFraction = o[0].XterrainHitFraction;
922 p.terrainRestitution = o[0].XterrainRestitution;
923 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
924
925 p.avatarFriction = o[0].XavatarFriction;
926 p.avatarStandingFriction = o[0].XavatarStandingFriction;
927 p.avatarDensity = o[0].XavatarDensity;
928 p.avatarRestitution = o[0].XavatarRestitution;
929 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
930 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
931 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
932 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
933
934 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
935
936 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
937 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
938 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
939 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
940 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
941 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
942 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
943 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
944
945 p.linksetImplementation = o[0].XlinksetImplementation;
946 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
947 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
948 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
949 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
950 p.linkConstraintERP = o[0].XlinkConstraintERP;
951 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
952 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
953 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
954 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
955
956 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
957 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
958
959
960 if (p.maxPersistantManifoldPoolSize > 0)
961 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
962 if (p.shouldDisableContactPoolDynamicAllocation !=0)
963 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
964 //if (p.maxCollisionAlgorithmPoolSize >0 )
965
966 DbvtBroadphase m_broadphase = new DbvtBroadphase();
967 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
968 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
969
970 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
971 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
972
973 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
974
975 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
976 world.UpdatedObjects = updateArray;
977 world.UpdatedCollisions = collisionArray;
978 world.WorldSettings.Params = p;
979 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
980 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
981 if (p.shouldRandomizeSolverOrder != 0)
982 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
983
984 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
985 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
986
987 if (p.shouldEnableFrictionCaching != 0)
988 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
989
990 if (p.numberOfSolverIterations > 0)
991 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
992
993
994 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
995 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
996 world.GetSolverInfo().m_globalCfm = 0.0f;
997 world.GetSolverInfo().m_tau = 0.6f;
998 world.GetSolverInfo().m_friction = 0.3f;
999 world.GetSolverInfo().m_maxErrorReduction = 20f;
1000 world.GetSolverInfo().m_numIterations = 10;
1001 world.GetSolverInfo().m_erp = 0.2f;
1002 world.GetSolverInfo().m_erp2 = 0.1f;
1003 world.GetSolverInfo().m_sor = 1.0f;
1004 world.GetSolverInfo().m_splitImpulse = false;
1005 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1006 world.GetSolverInfo().m_linearSlop = 0.0f;
1007 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1008 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1009 world.SetForceUpdateAllAabbs(true);
1010
1011
1012 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1013
1014 return world;
1015 }
1016 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1017 internal static bool SetConstraintParam2(object pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1018 {
1019 Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint;
1020 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1021 {
1022 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1023 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1024 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1025 }
1026 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1027 {
1028 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1029 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1030 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1031 }
1032 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1033 {
1034 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1035 }
1036 return true;
1037 }
1038
1039 internal static bool PushUpdate2(object pCollisionObject)
1040 {
1041 bool ret = false;
1042 RigidBody rb = pCollisionObject as RigidBody;
1043 if (rb != null)
1044 {
1045 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1046 if (sms != null)
1047 {
1048 IndexedMatrix wt = IndexedMatrix.Identity;
1049 sms.GetWorldTransform(out wt);
1050 sms.SetWorldTransform(ref wt, true);
1051 ret = true;
1052 }
1053 }
1054 return ret;
1055
1056 }
1057
1058 internal static bool IsCompound2(object pShape)
1059 {
1060 CollisionShape shape = pShape as CollisionShape;
1061 return shape.IsCompound();
1062 }
1063 internal static bool IsPloyhedral2(object pShape)
1064 {
1065 CollisionShape shape = pShape as CollisionShape;
1066 return shape.IsPolyhedral();
1067 }
1068 internal static bool IsConvex2d2(object pShape)
1069 {
1070 CollisionShape shape = pShape as CollisionShape;
1071 return shape.IsConvex2d();
1072 }
1073 internal static bool IsConvex2(object pShape)
1074 {
1075 CollisionShape shape = pShape as CollisionShape;
1076 return shape.IsConvex();
1077 }
1078 internal static bool IsNonMoving2(object pShape)
1079 {
1080 CollisionShape shape = pShape as CollisionShape;
1081 return shape.IsNonMoving();
1082 }
1083 internal static bool IsConcave2(object pShape)
1084 {
1085 CollisionShape shape = pShape as CollisionShape;
1086 return shape.IsConcave();
1087 }
1088 internal static bool IsInfinite2(object pShape)
1089 {
1090 CollisionShape shape = pShape as CollisionShape;
1091 return shape.IsInfinite();
1092 }
1093 internal static bool IsNativeShape2(object pShape)
1094 {
1095 CollisionShape shape = pShape as CollisionShape;
1096 bool ret;
1097 switch (shape.GetShapeType())
1098 {
1099 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1100 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1101 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1102 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1103 ret = true;
1104 break;
1105 default:
1106 ret = false;
1107 break;
1108 }
1109 return ret;
1110 }
1111 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1112 internal static object CreateGhostFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1113 {
1114 IndexedMatrix bodyTransform = new IndexedMatrix();
1115 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1116 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1117 GhostObject gObj = new PairCachingGhostObject();
1118 gObj.SetWorldTransform(bodyTransform);
1119 CollisionShape shape = pShape as CollisionShape;
1120 gObj.SetCollisionShape(shape);
1121 gObj.SetUserPointer(pLocalID);
1122 // TODO: Add to Special CollisionObjects!
1123 return gObj;
1124 }
1125
1126 public static void SetCollisionShape2(object pWorld, object pObj, object pShape)
1127 {
1128 var world = pWorld as DiscreteDynamicsWorld;
1129 var obj = pObj as CollisionObject;
1130 var shape = pShape as CollisionShape;
1131 obj.SetCollisionShape(shape);
1132
1133 }
1134 //(PhysicsScene.World.ptr, nativeShapeData)
1135 internal static object BuildNativeShape2(object pWorld, ShapeData pShapeData)
1136 {
1137 var world = pWorld as DiscreteDynamicsWorld;
1138 CollisionShape shape = null;
1139 switch (pShapeData.Type)
1140 {
1141 case BSPhysicsShapeType.SHAPE_BOX:
1142 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1143 break;
1144 case BSPhysicsShapeType.SHAPE_CONE:
1145 shape = new ConeShapeZ(0.5f, 1.0f);
1146 break;
1147 case BSPhysicsShapeType.SHAPE_CYLINDER:
1148 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1149 break;
1150 case BSPhysicsShapeType.SHAPE_SPHERE:
1151 shape = new SphereShape(0.5f);
1152 break;
1153
1154 }
1155 if (shape != null)
1156 {
1157 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1158 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1159 shape.SetLocalScaling(ref scaling);
1160
1161 }
1162 return shape;
1163 }
1164 //PhysicsScene.World.ptr, false
1165 internal static object CreateCompoundShape2(object pWorld, bool enableDynamicAabbTree)
1166 {
1167 return new CompoundShape(enableDynamicAabbTree);
1168 }
1169
1170 internal static int GetNumberOfCompoundChildren2(object pCompoundShape)
1171 {
1172 var compoundshape = pCompoundShape as CompoundShape;
1173 return compoundshape.GetNumChildShapes();
1174 }
1175 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1176 internal static void AddChildShapeToCompoundShape2(object pCShape, object paddShape, Vector3 displacementPos, Quaternion displacementRot)
1177 {
1178 IndexedMatrix relativeTransform = new IndexedMatrix();
1179 var compoundshape = pCShape as CompoundShape;
1180 var addshape = paddShape as CollisionShape;
1181
1182 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1183 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1184 compoundshape.AddChildShape(ref relativeTransform, addshape);
1185
1186 }
1187
1188 internal static object RemoveChildShapeFromCompoundShapeIndex2(object pCShape, int pii)
1189 {
1190 var compoundshape = pCShape as CompoundShape;
1191 CollisionShape ret = null;
1192 ret = compoundshape.GetChildShape(pii);
1193 compoundshape.RemoveChildShapeByIndex(pii);
1194 return ret;
1195 }
1196
1197 internal static object CreateGroundPlaneShape2(uint pLocalId, float pheight, float pcollisionMargin)
1198 {
1199 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1200 m_planeshape.SetMargin(pcollisionMargin);
1201 m_planeshape.SetUserPointer(pLocalId);
1202 return m_planeshape;
1203 }
1204
1205 internal static object CreateHingeConstraint2(object pWorld, object pBody1, object ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1206 {
1207 HingeConstraint constrain = null;
1208 var rb1 = pBody1 as RigidBody;
1209 var rb2 = ppBody2 as RigidBody;
1210 if (rb1 != null && rb2 != null)
1211 {
1212 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1213 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1214 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1215 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1216 var world = pWorld as DiscreteDynamicsWorld;
1217 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1218 }
1219 return constrain;
1220 }
1221
1222 internal static bool ReleaseHeightMapInfo2(object pMapInfo)
1223 {
1224 if (pMapInfo != null)
1225 {
1226 BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo;
1227 if (mapinfo.heightMap != null)
1228 mapinfo.heightMap = null;
1229
1230
1231 }
1232 return true;
1233 }
1234
1235 internal static object CreateHullShape2(object pWorld, int pHullCount, float[] pConvHulls)
1236 {
1237 CompoundShape compoundshape = new CompoundShape(false);
1238 var world = pWorld as DiscreteDynamicsWorld;
1239
1240
1241 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1242 int ii = 1;
1243
1244 for (int i = 0; i < pHullCount; i++)
1245 {
1246 int vertexCount = (int) pConvHulls[ii];
1247
1248 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1249 IndexedMatrix childTrans = IndexedMatrix.Identity;
1250 childTrans._origin = centroid;
1251
1252 List<IndexedVector3> virts = new List<IndexedVector3>();
1253 int ender = ((ii + 4) + (vertexCount*3));
1254 for (int iii = ii + 4; iii < ender; iii+=3)
1255 {
1256
1257 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1258 }
1259 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1260 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1261 compoundshape.AddChildShape(ref childTrans, convexShape);
1262 ii += (vertexCount*3 + 4);
1263 }
1264
1265
1266 return compoundshape;
1267 }
1268
1269 internal static object CreateMeshShape2(object pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1270 {
1271 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1272
1273 for (int iter = 0; iter < pVerticesCount; iter++)
1274 {
1275 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1276 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1277 }
1278
1279 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1280 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1281 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1282 var world = pWorld as DiscreteDynamicsWorld;
1283 IndexedMesh mesh = new IndexedMesh();
1284 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1285 mesh.m_numTriangles = pIndicesCount/3;
1286 mesh.m_numVertices = pVerticesCount;
1287 mesh.m_triangleIndexBase = indicesarr;
1288 mesh.m_vertexBase = vertices;
1289 mesh.m_vertexStride = 3;
1290 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1291 mesh.m_triangleIndexStride = 3;
1292
1293 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1294 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1295 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1296 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1297 // world.UpdateSingleAabb(meshShape);
1298 return meshShape;
1299
1300 }
1301 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1302 {
1303
1304 String fileName = "objTest3.raw";
1305 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1306 StreamWriter sw = new StreamWriter(completePath);
1307 IndexedMesh mesh = new IndexedMesh();
1308
1309 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1310 mesh.m_numTriangles = pIndicesCount / 3;
1311 mesh.m_numVertices = pVerticesCount;
1312 mesh.m_triangleIndexBase = indices;
1313 mesh.m_vertexBase = vertices;
1314 mesh.m_vertexStride = 3;
1315 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1316 mesh.m_triangleIndexStride = 3;
1317
1318 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1319 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1320
1321
1322
1323 for (int i = 0; i < pVerticesCount; i++)
1324 {
1325
1326 string s = vertices[indices[i * 3]].ToString("0.0000");
1327 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1328 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1329
1330 sw.Write(s + "\n");
1331 }
1332
1333 sw.Close();
1334 }
1335 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1336 {
1337
1338 String fileName = "objTest6.raw";
1339 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1340 StreamWriter sw = new StreamWriter(completePath);
1341 IndexedMesh mesh = new IndexedMesh();
1342
1343 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1344 mesh.m_numTriangles = pIndicesCount / 3;
1345 mesh.m_numVertices = pVerticesCount;
1346 mesh.m_triangleIndexBase = indices;
1347 mesh.m_vertexBase = vertices;
1348 mesh.m_vertexStride = 3;
1349 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1350 mesh.m_triangleIndexStride = 3;
1351
1352 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1353 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1354
1355
1356 sw.WriteLine("Indices");
1357 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1358 for (int iter = 0; iter < indices.Length; iter++)
1359 {
1360 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1361 }
1362 sw.WriteLine("VerticesFloats");
1363 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1364 for (int iter = 0; iter < vertices.Length; iter++)
1365 {
1366 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1367 }
1368
1369 // for (int i = 0; i < pVerticesCount; i++)
1370 // {
1371 //
1372 // string s = vertices[indices[i * 3]].ToString("0.0000");
1373 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1374 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1375 //
1376 // sw.Write(s + "\n");
1377 //}
1378
1379 sw.Close();
1380 }
1381 //PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin
1382 internal static object CreateHeightMapInfo2(object pWorld, uint pId, Vector3 pminCoords, Vector3 pmaxCoords, float[] pheightMap, float pCollisionMargin)
1383 {
1384 BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(pId, pheightMap, null);
1385 mapInfo.heightMap = null;
1386 mapInfo.minCoords = pminCoords;
1387 mapInfo.maxCoords = pmaxCoords;
1388 mapInfo.sizeX = (int) (pmaxCoords.X - pminCoords.X);
1389 mapInfo.sizeY = (int) (pmaxCoords.Y - pminCoords.Y);
1390 mapInfo.ID = pId;
1391 mapInfo.minZ = pminCoords.Z;
1392 mapInfo.maxZ = pmaxCoords.Z;
1393 mapInfo.collisionMargin = pCollisionMargin;
1394 if (mapInfo.minZ == mapInfo.maxZ)
1395 mapInfo.minZ -= 0.2f;
1396 mapInfo.heightMap = pheightMap;
1397
1398 return mapInfo;
1399
1400 }
1401
1402 internal static object CreateTerrainShape2(object pMapInfo)
1403 {
1404 BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo;
1405 const int upAxis = 2;
1406 const float scaleFactor = 1.0f;
1407 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)mapinfo.sizeX, (int)mapinfo.sizeY,
1408 mapinfo.heightMap, scaleFactor,
1409 mapinfo.minZ, mapinfo.maxZ, upAxis,
1410 false);
1411 terrainShape.SetMargin(mapinfo.collisionMargin + 0.5f);
1412 terrainShape.SetUseDiamondSubdivision(true);
1413 terrainShape.SetUserPointer(mapinfo.ID);
1414 return terrainShape;
1415 }
1416
1417 internal static bool TranslationalLimitMotor2(object pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1418 {
1419 TypedConstraint tconstrain = pConstraint as TypedConstraint;
1420 bool onOff = ponOff != 0;
1421 bool ret = false;
1422
1423 switch (tconstrain.GetConstraintType())
1424 {
1425 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1426 Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint;
1427 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1428 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1429 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1430 ret = true;
1431 break;
1432 }
1433
1434
1435 return ret;
1436
1437 }
1438
1439 internal static int PhysicsStep2(object pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1440 {
1441 int epic = PhysicsStepint2(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1442 out collidersCount, out colliders);
1443 return epic;
1444 }
1445
1446 private static int PhysicsStepint2(object pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders)
1447 {
1448 int numSimSteps = 0;
1449
1450
1451 //if (updatedEntities is null)
1452 // updatedEntities = new List<BulletXNA.EntityProperties>();
1453
1454 //if (colliders is null)
1455 // colliders = new List<BulletXNA.CollisionDesc>();
1456
1457
1458 if (pWorld is DiscreteDynamicsWorld)
1459 {
1460 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
1461
1462 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1463 int updates = 0;
1464
1465 updatedEntityCount = world.UpdatedObjects.Count;
1466 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1467 updatedEntityCount = updatedEntities.Count;
1468 world.UpdatedObjects.Clear();
1469
1470
1471 collidersCount = world.UpdatedCollisions.Count;
1472 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1473
1474 world.UpdatedCollisions.Clear();
1475 m_collisionsThisFrame = 0;
1476 int numManifolds = world.GetDispatcher().GetNumManifolds();
1477 for (int j = 0; j < numManifolds; j++)
1478 {
1479 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1480 int numContacts = contactManifold.GetNumContacts();
1481 if (numContacts == 0)
1482 continue;
1483
1484 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1485 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1486
1487 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1488 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1489 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1490
1491 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1492 m_collisionsThisFrame ++;
1493 if (m_collisionsThisFrame >= 9999999)
1494 break;
1495
1496
1497 }
1498
1499
1500 }
1501 else
1502 {
1503 //if (updatedEntities is null)
1504 updatedEntities = new List<BulletXNA.EntityProperties>();
1505 updatedEntityCount = 0;
1506 //if (colliders is null)
1507 colliders = new List<BulletXNA.CollisionDesc>();
1508 collidersCount = 0;
1509 }
1510 return numSimSteps;
1511 }
1512
1513 private static void RecordCollision(CollisionWorld world,CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1514 {
1515
1516 IndexedVector3 contactNormal = norm;
1517 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1518 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1519 {
1520 return;
1521 }
1522 uint idA = (uint)objA.GetUserPointer();
1523 uint idB = (uint)objB.GetUserPointer();
1524 if (idA > idB)
1525 {
1526 uint temp = idA;
1527 idA = idB;
1528 idB = temp;
1529 contactNormal = -contactNormal;
1530 }
1531
1532 ulong collisionID = ((ulong) idA << 32) | idB;
1533
1534 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1535 {
1536 aID = idA,
1537 bID = idB,
1538 point = contact,
1539 normal = contactNormal
1540 };
1541 world.UpdatedCollisions.Add(cDesc);
1542 m_collisionsThisFrame++;
1543
1544
1545 }
1546 private static EntityProperties GetDebugProperties(object pWorld, object pBody)
1547 {
1548 EntityProperties ent = new EntityProperties();
1549 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
1550 RigidBody body = pBody as RigidBody;
1551 IndexedMatrix transform = body.GetWorldTransform();
1552 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1553 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1554 IndexedQuaternion rotation = transform.GetRotation();
1555 ent.Acceleration = Vector3.Zero;
1556 ent.ID = (uint)body.GetUserPointer();
1557 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1558 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1559 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1560 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1561 return ent;
1562
1563
1564 }
1565
1566
1567 internal static Vector3 GetLocalScaling2(object pBody)
1568 {
1569 CollisionShape shape = pBody as CollisionShape;
1570 IndexedVector3 scale = shape.GetLocalScaling();
1571 return new Vector3(scale.X,scale.Y,scale.Z);
1572 }
1573
1574 internal static bool RayCastGround(object pWorld, Vector3 _RayOrigin, float pRayHeight, object NotMe)
1575 {
1576 DynamicsWorld world = pWorld as DynamicsWorld;
1577 if (world != null)
1578 {
1579 if (NotMe is CollisionObject || NotMe is RigidBody)
1580 {
1581 CollisionObject AvoidBody = NotMe as CollisionObject;
1582
1583 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1584 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1585 using (
1586 ClosestNotMeRayResultCallback rayCallback = new ClosestNotMeRayResultCallback(rOrigin,
1587 rEnd, AvoidBody)
1588 )
1589 {
1590 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1591 if (rayCallback.HasHit())
1592 {
1593 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1594
1595 }
1596 return rayCallback.HasHit();
1597 }
1598 }
1599 }
1600 return false;
1601 }
1602}
1603}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs
new file mode 100644
index 0000000..f509dc4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs
@@ -0,0 +1,280 @@
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.BulletSNPlugin
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 BulletWorld
39{
40 public BulletWorld(uint worldId, BSScene bss, object xx)
41 {
42 ptr = xx;
43 worldID = worldId;
44 physicsScene = bss;
45 }
46 public object 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, null)
56 {
57 }
58 public BulletBody(uint id, object xx)
59 {
60 ID = id;
61 ptr = xx;
62 collisionType = CollisionType.Static;
63 }
64 public object ptr;
65 public uint ID;
66 public CollisionType collisionType;
67
68 public void Clear()
69 {
70 ptr = null;
71 }
72 public bool HasPhysicalBody { get { return ptr != null; } }
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());
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(object xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
102 {
103 }
104 public BulletShape(object xx, BSPhysicsShapeType typ)
105 {
106 ptr = xx;
107 type = typ;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public object ptr;
112 public BSPhysicsShapeType type;
113 public System.UInt64 shapeKey;
114 public bool isNativeShape;
115
116 public void Clear()
117 {
118 ptr = null;
119 }
120 public bool HasPhysicalShape { get { return ptr != null; } }
121
122 public override string ToString()
123 {
124 StringBuilder buff = new StringBuilder();
125 buff.Append("<p=");
126 buff.Append(ptr.ToString());
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(object xx)
142 {
143 ptr = xx;
144 }
145 public object ptr;
146
147 public void Clear()
148 {
149 ptr = null;
150 }
151 public bool HasPhysicalConstraint { get { return ptr != null; } }
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, object 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 object 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 public float collisionMargin { get; set; }
182}
183
184// The general class of collsion object.
185public enum CollisionType
186{
187 Avatar,
188 Groundplane,
189 Terrain,
190 Static,
191 Dynamic,
192 VolumeDetect,
193 // Linkset, // A linkset should be either Static or Dynamic
194 LinksetChild,
195 Unknown
196};
197
198// Hold specification of group and mask collision flags for a CollisionType
199public struct CollisionTypeFilterGroup
200{
201 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
202 {
203 type = t;
204 group = g;
205 mask = m;
206 }
207 public CollisionType type;
208 public uint group;
209 public uint mask;
210};
211
212 /* NOTE: old definitions kept for reference. Delete when things are working.
213 // The collsion filters and masked are defined in one place -- don't want them scattered
214 AvatarGroup = BCharacterGroup,
215 AvatarMask = BAllGroup,
216 ObjectGroup = BSolidGroup,
217 ObjectMask = BAllGroup,
218 StaticObjectGroup = BStaticGroup,
219 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
220 LinksetGroup = BLinksetGroup,
221 LinksetMask = BAllGroup,
222 LinksetChildGroup = BLinksetChildGroup,
223 LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
224 VolumeDetectGroup = BSensorTrigger,
225 VolumeDetectMask = ~BSensorTrigger,
226 TerrainGroup = BTerrainGroup,
227 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
228 GroundPlaneGroup = BGroundPlaneGroup,
229 GroundPlaneMask = BAllGroup
230 */
231
232public static class BulletSimData
233{
234
235// Map of collisionTypes to flags for collision groups and masks.
236// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
237// but, instead, use references to this dictionary. Finding and debugging
238// collision flag problems will be made easier.
239public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
240 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
241{
242 { CollisionType.Avatar,
243 new CollisionTypeFilterGroup(CollisionType.Avatar,
244 (uint)CollisionFilterGroups.BCharacterGroup,
245 (uint)CollisionFilterGroups.BAllGroup)
246 },
247 { CollisionType.Groundplane,
248 new CollisionTypeFilterGroup(CollisionType.Groundplane,
249 (uint)CollisionFilterGroups.BGroundPlaneGroup,
250 (uint)CollisionFilterGroups.BAllGroup)
251 },
252 { CollisionType.Terrain,
253 new CollisionTypeFilterGroup(CollisionType.Terrain,
254 (uint)CollisionFilterGroups.BTerrainGroup,
255 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
256 },
257 { CollisionType.Static,
258 new CollisionTypeFilterGroup(CollisionType.Static,
259 (uint)CollisionFilterGroups.BStaticGroup,
260 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
261 },
262 { CollisionType.Dynamic,
263 new CollisionTypeFilterGroup(CollisionType.Dynamic,
264 (uint)CollisionFilterGroups.BSolidGroup,
265 (uint)(CollisionFilterGroups.BAllGroup))
266 },
267 { CollisionType.VolumeDetect,
268 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
269 (uint)CollisionFilterGroups.BSensorTrigger,
270 (uint)(~CollisionFilterGroups.BSensorTrigger))
271 },
272 { CollisionType.LinksetChild,
273 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
274 (uint)CollisionFilterGroups.BTerrainGroup,
275 (uint)(CollisionFilterGroups.BNoneGroup))
276 },
277};
278
279}
280}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
new file mode 100755
index 0000000..ae54499
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -0,0 +1,1885 @@
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.Reflection;
30using System.Runtime.InteropServices;
31using System.Security;
32using System.Text;
33
34using OpenSim.Framework;
35
36using OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40public sealed class BSAPIUnman : BSAPITemplate
41{
42
43private sealed class BulletWorldUnman : BulletWorld
44{
45 public IntPtr ptr;
46 public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx)
47 : base(id, physScene)
48 {
49 ptr = xx;
50 }
51}
52
53private sealed class BulletBodyUnman : BulletBody
54{
55 public IntPtr ptr;
56 public BulletBodyUnman(uint id, IntPtr xx)
57 : base(id)
58 {
59 ptr = xx;
60 }
61 public override bool HasPhysicalBody
62 {
63 get { return ptr != IntPtr.Zero; }
64 }
65 public override void Clear()
66 {
67 ptr = IntPtr.Zero;
68 }
69 public override string AddrString
70 {
71 get { return ptr.ToString("X"); }
72 }
73}
74
75private sealed class BulletShapeUnman : BulletShape
76{
77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base()
80 {
81 ptr = xx;
82 type = typ;
83 }
84 public override bool HasPhysicalShape
85 {
86 get { return ptr != IntPtr.Zero; }
87 }
88 public override void Clear()
89 {
90 ptr = IntPtr.Zero;
91 }
92 public override BulletShape Clone()
93 {
94 return new BulletShapeUnman(ptr, type);
95 }
96 public override bool ReferenceSame(BulletShape other)
97 {
98 BulletShapeUnman otheru = other as BulletShapeUnman;
99 return (otheru != null) && (this.ptr == otheru.ptr);
100
101 }
102 public override string AddrString
103 {
104 get { return ptr.ToString("X"); }
105 }
106}
107private sealed class BulletConstraintUnman : BulletConstraint
108{
109 public BulletConstraintUnman(IntPtr xx) : base()
110 {
111 ptr = xx;
112 }
113 public IntPtr ptr;
114
115 public override void Clear()
116 {
117 ptr = IntPtr.Zero;
118 }
119 public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
120
121 // Used for log messages for a unique display of the memory/object allocated to this instance
122 public override string AddrString
123 {
124 get { return ptr.ToString("X"); }
125 }
126}
127
128// We pin the memory passed between the managed and unmanaged code.
129GCHandle m_paramsHandle;
130private GCHandle m_collisionArrayPinnedHandle;
131private GCHandle m_updateArrayPinnedHandle;
132
133// Handle to the callback used by the unmanaged code to call into the managed code.
134// Used for debug logging.
135// Need to store the handle in a persistant variable so it won't be freed.
136private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle;
137
138private BSScene PhysicsScene { get; set; }
139
140public override string BulletEngineName { get { return "BulletUnmanaged"; } }
141public override string BulletEngineVersion { get; protected set; }
142
143public BSAPIUnman(string paramName, BSScene physScene)
144{
145 PhysicsScene = physScene;
146
147 // Do something fancy with the paramName to get the right DLL implementation
148 // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc.
149 if (Util.IsWindows())
150 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
151 // If not Windows, loading is performed by the
152 // Mono loader as specified in
153 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
154}
155
156// Initialization and simulation
157public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
158 int maxCollisions, ref CollisionDesc[] collisionArray,
159 int maxUpdates, ref EntityProperties[] updateArray
160 )
161{
162 // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code
163 m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned);
164 m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned);
165 m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned);
166
167 // If Debug logging level, enable logging from the unmanaged code
168 m_DebugLogCallbackHandle = null;
169 if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled)
170 {
171 BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
172 if (PhysicsScene.PhysicsLogging.Enabled)
173 // The handle is saved in a variable to make sure it doesn't get freed after this call
174 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog);
175 else
176 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger);
177 }
178
179 // Get the version of the DLL
180 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
181 // BulletEngineVersion = BulletSimAPI.GetVersion2();
182 BulletEngineVersion = "";
183
184 // Call the unmanaged code with the buffers and other information
185 return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(),
186 maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
187 maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
188 m_DebugLogCallbackHandle));
189
190}
191
192// Called directly from unmanaged code so don't do much
193private void BulletLogger(string msg)
194{
195 BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg);
196}
197
198// Called directly from unmanaged code so don't do much
199private void BulletLoggerPhysLog(string msg)
200{
201 PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg);
202}
203
204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
205 out int updatedEntityCount, out int collidersCount)
206{
207 BulletWorldUnman worldu = world as BulletWorldUnman;
208 return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
209}
210
211public override void Shutdown(BulletWorld world)
212{
213 BulletWorldUnman worldu = world as BulletWorldUnman;
214 BSAPICPP.Shutdown2(worldu.ptr);
215
216 if (m_paramsHandle.IsAllocated)
217 {
218 m_paramsHandle.Free();
219 }
220 if (m_collisionArrayPinnedHandle.IsAllocated)
221 {
222 m_collisionArrayPinnedHandle.Free();
223 }
224 if (m_updateArrayPinnedHandle.IsAllocated)
225 {
226 m_updateArrayPinnedHandle.Free();
227 }
228}
229
230public override bool PushUpdate(BulletBody obj)
231{
232 BulletBodyUnman bodyu = obj as BulletBodyUnman;
233 return BSAPICPP.PushUpdate2(bodyu.ptr);
234}
235
236public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
237{
238 BulletWorldUnman worldu = world as BulletWorldUnman;
239 return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
240}
241
242// =====================================================================================
243// Mesh, hull, shape and body creation helper routines
244public override BulletShape CreateMeshShape(BulletWorld world,
245 int indicesCount, int[] indices,
246 int verticesCount, float[] vertices)
247{
248 BulletWorldUnman worldu = world as BulletWorldUnman;
249 return new BulletShapeUnman(
250 BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
251 BSPhysicsShapeType.SHAPE_MESH);
252}
253
254public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
255{
256 BulletWorldUnman worldu = world as BulletWorldUnman;
257 return new BulletShapeUnman(
258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
259 BSPhysicsShapeType.SHAPE_HULL);
260}
261
262public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
263{
264 BulletWorldUnman worldu = world as BulletWorldUnman;
265 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
266 return new BulletShapeUnman(
267 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
268 BSPhysicsShapeType.SHAPE_HULL);
269}
270
271public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
272{
273 BulletWorldUnman worldu = world as BulletWorldUnman;
274 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
275}
276
277public override bool IsNativeShape(BulletShape shape)
278{
279 BulletShapeUnman shapeu = shape as BulletShapeUnman;
280 if (shapeu != null && shapeu.HasPhysicalShape)
281 return BSAPICPP.IsNativeShape2(shapeu.ptr);
282 return false;
283}
284
285public override void SetShapeCollisionMargin(BulletShape shape, float margin)
286{
287 BulletShapeUnman shapeu = shape as BulletShapeUnman;
288 if (shapeu != null && shapeu.HasPhysicalShape)
289 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin);
290}
291
292public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
297 BSPhysicsShapeType.SHAPE_CAPSULE);
298}
299
300public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
301{
302 BulletWorldUnman worldu = world as BulletWorldUnman;
303 return new BulletShapeUnman(
304 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
305 BSPhysicsShapeType.SHAPE_COMPOUND);
306
307}
308
309public override int GetNumberOfCompoundChildren(BulletShape shape)
310{
311 BulletShapeUnman shapeu = shape as BulletShapeUnman;
312 if (shapeu != null && shapeu.HasPhysicalShape)
313 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
314 return 0;
315}
316
317public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
318{
319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
320 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
321 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
322}
323
324public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
325{
326 BulletShapeUnman shapeu = shape as BulletShapeUnman;
327 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
328}
329
330public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
331{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman;
333 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
334}
335
336public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
337{
338 BulletShapeUnman shapeu = shape as BulletShapeUnman;
339 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
340 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
341}
342
343public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
344{
345 BulletShapeUnman shapeu = pShape as BulletShapeUnman;
346 BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
347}
348
349public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
350{
351 BulletShapeUnman shapeu = shape as BulletShapeUnman;
352 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
353}
354
355public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
356{
357 BulletWorldUnman worldu = world as BulletWorldUnman;
358 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
359 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type);
360}
361
362public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
363{
364 BulletWorldUnman worldu = world as BulletWorldUnman;
365 BulletShapeUnman shapeu = shape as BulletShapeUnman;
366 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
367}
368
369public override CollisionObjectTypes GetBodyType(BulletBody obj)
370{
371 BulletBodyUnman bodyu = obj as BulletBodyUnman;
372 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
373}
374
375public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
376{
377 BulletWorldUnman worldu = world as BulletWorldUnman;
378 BulletShapeUnman shapeu = shape as BulletShapeUnman;
379 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
380}
381
382public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
383{
384 BulletShapeUnman shapeu = shape as BulletShapeUnman;
385 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
386}
387
388public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
389{
390 BulletWorldUnman worldu = world as BulletWorldUnman;
391 BulletShapeUnman shapeu = shape as BulletShapeUnman;
392 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
393}
394
395public override void DestroyObject(BulletWorld world, BulletBody obj)
396{
397 BulletWorldUnman worldu = world as BulletWorldUnman;
398 BulletBodyUnman bodyu = obj as BulletBodyUnman;
399 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
400}
401
402// =====================================================================================
403// Terrain creation and helper routines
404public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
405{
406 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
407}
408
409public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
410 float scaleFactor, float collisionMargin)
411{
412 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
413 BSPhysicsShapeType.SHAPE_TERRAIN);
414}
415
416// =====================================================================================
417// Constraint creation and helper routines
418public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 frame1loc, Quaternion frame1rot,
420 Vector3 frame2loc, Quaternion frame2rot,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
422{
423 BulletWorldUnman worldu = world as BulletWorldUnman;
424 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
425 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
426 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
427 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
428}
429
430public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
431 Vector3 joinPoint,
432 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
433{
434 BulletWorldUnman worldu = world as BulletWorldUnman;
435 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
436 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
437 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
438 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
439}
440
441public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
442 Vector3 pivotinA, Vector3 pivotinB,
443 Vector3 axisInA, Vector3 axisInB,
444 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
445{
446 BulletWorldUnman worldu = world as BulletWorldUnman;
447 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
448 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
449 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
450 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
451}
452
453public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
454{
455 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
456 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
457}
458
459public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
460{
461 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
462 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
463}
464
465public override bool SetFrames(BulletConstraint constrain,
466 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
467{
468 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
469 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
470}
471
472public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
473{
474 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
475 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
476}
477
478public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
479{
480 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
481 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
482}
483
484public override bool UseFrameOffset(BulletConstraint constrain, float enable)
485{
486 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
487 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
488}
489
490public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
491{
492 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
493 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
494}
495
496public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
497{
498 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
499 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
500}
501
502public override bool CalculateTransforms(BulletConstraint constrain)
503{
504 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
505 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
506}
507
508public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
509{
510 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
511 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
512}
513
514public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
515{
516 BulletWorldUnman worldu = world as BulletWorldUnman;
517 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
518 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
519}
520
521// =====================================================================================
522// btCollisionWorld entries
523public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
524{
525 BulletWorldUnman worldu = world as BulletWorldUnman;
526 BulletBodyUnman bodyu = obj as BulletBodyUnman;
527 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
528}
529
530public override void UpdateAabbs(BulletWorld world)
531{
532 BulletWorldUnman worldu = world as BulletWorldUnman;
533 BSAPICPP.UpdateAabbs2(worldu.ptr);
534}
535
536public override bool GetForceUpdateAllAabbs(BulletWorld world)
537{
538 BulletWorldUnman worldu = world as BulletWorldUnman;
539 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
540}
541
542public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
543{
544 BulletWorldUnman worldu = world as BulletWorldUnman;
545 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
546}
547
548// =====================================================================================
549// btDynamicsWorld entries
550public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
551{
552 BulletWorldUnman worldu = world as BulletWorldUnman;
553 BulletBodyUnman bodyu = obj as BulletBodyUnman;
554
555 // Bullet resets several variables when an object is added to the world.
556 // Gravity is reset to world default depending on the static/dynamic
557 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
558 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
559
560 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
561
562 if (ret)
563 {
564 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
565 obj.ApplyCollisionMask(world.physicsScene);
566 }
567 return ret;
568}
569
570public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
571{
572 BulletWorldUnman worldu = world as BulletWorldUnman;
573 BulletBodyUnman bodyu = obj as BulletBodyUnman;
574 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
575}
576
577public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
578{
579 BulletWorldUnman worldu = world as BulletWorldUnman;
580 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
581 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
582}
583
584public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
585{
586 BulletWorldUnman worldu = world as BulletWorldUnman;
587 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
588 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
589}
590// =====================================================================================
591// btCollisionObject entries
592public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
593{
594 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
595 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
596}
597
598public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
599{
600 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
601 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
602}
603
604public override bool HasAnisotripicFriction(BulletConstraint constrain)
605{
606 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
607 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
608}
609
610public override void SetContactProcessingThreshold(BulletBody obj, float val)
611{
612 BulletBodyUnman bodyu = obj as BulletBodyUnman;
613 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
614}
615
616public override float GetContactProcessingThreshold(BulletBody obj)
617{
618 BulletBodyUnman bodyu = obj as BulletBodyUnman;
619 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
620}
621
622public override bool IsStaticObject(BulletBody obj)
623{
624 BulletBodyUnman bodyu = obj as BulletBodyUnman;
625 return BSAPICPP.IsStaticObject2(bodyu.ptr);
626}
627
628public override bool IsKinematicObject(BulletBody obj)
629{
630 BulletBodyUnman bodyu = obj as BulletBodyUnman;
631 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
632}
633
634public override bool IsStaticOrKinematicObject(BulletBody obj)
635{
636 BulletBodyUnman bodyu = obj as BulletBodyUnman;
637 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
638}
639
640public override bool HasContactResponse(BulletBody obj)
641{
642 BulletBodyUnman bodyu = obj as BulletBodyUnman;
643 return BSAPICPP.HasContactResponse2(bodyu.ptr);
644}
645
646public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
647{
648 BulletWorldUnman worldu = world as BulletWorldUnman;
649 BulletBodyUnman bodyu = obj as BulletBodyUnman;
650 BulletShapeUnman shapeu = shape as BulletShapeUnman;
651 if (worldu != null && bodyu != null)
652 {
653 // Special case to allow the caller to zero out the reference to any physical shape
654 if (shapeu != null)
655 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
656 else
657 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
658 }
659}
660
661public override BulletShape GetCollisionShape(BulletBody obj)
662{
663 BulletBodyUnman bodyu = obj as BulletBodyUnman;
664 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
665}
666
667public override int GetActivationState(BulletBody obj)
668{
669 BulletBodyUnman bodyu = obj as BulletBodyUnman;
670 return BSAPICPP.GetActivationState2(bodyu.ptr);
671}
672
673public override void SetActivationState(BulletBody obj, int state)
674{
675 BulletBodyUnman bodyu = obj as BulletBodyUnman;
676 BSAPICPP.SetActivationState2(bodyu.ptr, state);
677}
678
679public override void SetDeactivationTime(BulletBody obj, float dtime)
680{
681 BulletBodyUnman bodyu = obj as BulletBodyUnman;
682 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
683}
684
685public override float GetDeactivationTime(BulletBody obj)
686{
687 BulletBodyUnman bodyu = obj as BulletBodyUnman;
688 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
689}
690
691public override void ForceActivationState(BulletBody obj, ActivationState state)
692{
693 BulletBodyUnman bodyu = obj as BulletBodyUnman;
694 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
695}
696
697public override void Activate(BulletBody obj, bool forceActivation)
698{
699 BulletBodyUnman bodyu = obj as BulletBodyUnman;
700 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
701}
702
703public override bool IsActive(BulletBody obj)
704{
705 BulletBodyUnman bodyu = obj as BulletBodyUnman;
706 return BSAPICPP.IsActive2(bodyu.ptr);
707}
708
709public override void SetRestitution(BulletBody obj, float val)
710{
711 BulletBodyUnman bodyu = obj as BulletBodyUnman;
712 BSAPICPP.SetRestitution2(bodyu.ptr, val);
713}
714
715public override float GetRestitution(BulletBody obj)
716{
717 BulletBodyUnman bodyu = obj as BulletBodyUnman;
718 return BSAPICPP.GetRestitution2(bodyu.ptr);
719}
720
721public override void SetFriction(BulletBody obj, float val)
722{
723 BulletBodyUnman bodyu = obj as BulletBodyUnman;
724 BSAPICPP.SetFriction2(bodyu.ptr, val);
725}
726
727public override float GetFriction(BulletBody obj)
728{
729 BulletBodyUnman bodyu = obj as BulletBodyUnman;
730 return BSAPICPP.GetFriction2(bodyu.ptr);
731}
732
733public override Vector3 GetPosition(BulletBody obj)
734{
735 BulletBodyUnman bodyu = obj as BulletBodyUnman;
736 return BSAPICPP.GetPosition2(bodyu.ptr);
737}
738
739public override Quaternion GetOrientation(BulletBody obj)
740{
741 BulletBodyUnman bodyu = obj as BulletBodyUnman;
742 return BSAPICPP.GetOrientation2(bodyu.ptr);
743}
744
745public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
746{
747 BulletBodyUnman bodyu = obj as BulletBodyUnman;
748 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
749}
750
751 /*
752public override IntPtr GetBroadphaseHandle(BulletBody obj)
753{
754 BulletBodyUnman bodyu = obj as BulletBodyUnman;
755 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
756}
757
758public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
759{
760 BulletBodyUnman bodyu = obj as BulletBodyUnman;
761 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
762}
763 */
764
765public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
766{
767 BulletBodyUnman bodyu = obj as BulletBodyUnman;
768 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
769}
770
771public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
772{
773 BulletBodyUnman bodyu = obj as BulletBodyUnman;
774 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
775}
776
777public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
778{
779 BulletBodyUnman bodyu = obj as BulletBodyUnman;
780 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
781}
782
783public override float GetHitFraction(BulletBody obj)
784{
785 BulletBodyUnman bodyu = obj as BulletBodyUnman;
786 return BSAPICPP.GetHitFraction2(bodyu.ptr);
787}
788
789public override void SetHitFraction(BulletBody obj, float val)
790{
791 BulletBodyUnman bodyu = obj as BulletBodyUnman;
792 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
793}
794
795public override CollisionFlags GetCollisionFlags(BulletBody obj)
796{
797 BulletBodyUnman bodyu = obj as BulletBodyUnman;
798 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
799}
800
801public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
802{
803 BulletBodyUnman bodyu = obj as BulletBodyUnman;
804 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
805}
806
807public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
811}
812
813public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
817}
818
819public override float GetCcdMotionThreshold(BulletBody obj)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
823}
824
825
826public override void SetCcdMotionThreshold(BulletBody obj, float val)
827{
828 BulletBodyUnman bodyu = obj as BulletBodyUnman;
829 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
830}
831
832public override float GetCcdSweptSphereRadius(BulletBody obj)
833{
834 BulletBodyUnman bodyu = obj as BulletBodyUnman;
835 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
836}
837
838public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
839{
840 BulletBodyUnman bodyu = obj as BulletBodyUnman;
841 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
842}
843
844public override IntPtr GetUserPointer(BulletBody obj)
845{
846 BulletBodyUnman bodyu = obj as BulletBodyUnman;
847 return BSAPICPP.GetUserPointer2(bodyu.ptr);
848}
849
850public override void SetUserPointer(BulletBody obj, IntPtr val)
851{
852 BulletBodyUnman bodyu = obj as BulletBodyUnman;
853 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
854}
855
856// =====================================================================================
857// btRigidBody entries
858public override void ApplyGravity(BulletBody obj)
859{
860 BulletBodyUnman bodyu = obj as BulletBodyUnman;
861 BSAPICPP.ApplyGravity2(bodyu.ptr);
862}
863
864public override void SetGravity(BulletBody obj, Vector3 val)
865{
866 BulletBodyUnman bodyu = obj as BulletBodyUnman;
867 BSAPICPP.SetGravity2(bodyu.ptr, val);
868}
869
870public override Vector3 GetGravity(BulletBody obj)
871{
872 BulletBodyUnman bodyu = obj as BulletBodyUnman;
873 return BSAPICPP.GetGravity2(bodyu.ptr);
874}
875
876public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
877{
878 BulletBodyUnman bodyu = obj as BulletBodyUnman;
879 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
880}
881
882public override void SetLinearDamping(BulletBody obj, float lin_damping)
883{
884 BulletBodyUnman bodyu = obj as BulletBodyUnman;
885 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
886}
887
888public override void SetAngularDamping(BulletBody obj, float ang_damping)
889{
890 BulletBodyUnman bodyu = obj as BulletBodyUnman;
891 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
892}
893
894public override float GetLinearDamping(BulletBody obj)
895{
896 BulletBodyUnman bodyu = obj as BulletBodyUnman;
897 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
898}
899
900public override float GetAngularDamping(BulletBody obj)
901{
902 BulletBodyUnman bodyu = obj as BulletBodyUnman;
903 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
904}
905
906public override float GetLinearSleepingThreshold(BulletBody obj)
907{
908 BulletBodyUnman bodyu = obj as BulletBodyUnman;
909 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
910}
911
912public override void ApplyDamping(BulletBody obj, float timeStep)
913{
914 BulletBodyUnman bodyu = obj as BulletBodyUnman;
915 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
916}
917
918public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
919{
920 BulletBodyUnman bodyu = obj as BulletBodyUnman;
921 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
922}
923
924public override Vector3 GetLinearFactor(BulletBody obj)
925{
926 BulletBodyUnman bodyu = obj as BulletBodyUnman;
927 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
928}
929
930public override void SetLinearFactor(BulletBody obj, Vector3 factor)
931{
932 BulletBodyUnman bodyu = obj as BulletBodyUnman;
933 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
934}
935
936public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
937{
938 BulletBodyUnman bodyu = obj as BulletBodyUnman;
939 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
940}
941
942// Add a force to the object as if its mass is one.
943// Deep down in Bullet: m_totalForce += force*m_linearFactor;
944public override void ApplyCentralForce(BulletBody obj, Vector3 force)
945{
946 BulletBodyUnman bodyu = obj as BulletBodyUnman;
947 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
948}
949
950// Set the force being applied to the object as if its mass is one.
951public override void SetObjectForce(BulletBody obj, Vector3 force)
952{
953 BulletBodyUnman bodyu = obj as BulletBodyUnman;
954 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
955}
956
957public override Vector3 GetTotalForce(BulletBody obj)
958{
959 BulletBodyUnman bodyu = obj as BulletBodyUnman;
960 return BSAPICPP.GetTotalForce2(bodyu.ptr);
961}
962
963public override Vector3 GetTotalTorque(BulletBody obj)
964{
965 BulletBodyUnman bodyu = obj as BulletBodyUnman;
966 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
967}
968
969public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
970{
971 BulletBodyUnman bodyu = obj as BulletBodyUnman;
972 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
973}
974
975public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
976{
977 BulletBodyUnman bodyu = obj as BulletBodyUnman;
978 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
979}
980
981public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
982{
983 BulletBodyUnman bodyu = obj as BulletBodyUnman;
984 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
985}
986
987// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
988public override void ApplyTorque(BulletBody obj, Vector3 torque)
989{
990 BulletBodyUnman bodyu = obj as BulletBodyUnman;
991 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
992}
993
994// Apply force at the given point. Will add torque to the object.
995// Deep down in Bullet: applyCentralForce(force);
996// applyTorque(rel_pos.cross(force*m_linearFactor));
997public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
998{
999 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1000 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1001}
1002
1003// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1004// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1005public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1006{
1007 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1008 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1009}
1010
1011// Apply impulse to the object's torque. Force is scaled by object's mass.
1012// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1013public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1014{
1015 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1016 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1017}
1018
1019// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1020// Deep down in Bullet: applyCentralImpulse(impulse);
1021// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1022public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1023{
1024 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1025 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1026}
1027
1028public override void ClearForces(BulletBody obj)
1029{
1030 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1031 BSAPICPP.ClearForces2(bodyu.ptr);
1032}
1033
1034public override void ClearAllForces(BulletBody obj)
1035{
1036 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1037 BSAPICPP.ClearAllForces2(bodyu.ptr);
1038}
1039
1040public override void UpdateInertiaTensor(BulletBody obj)
1041{
1042 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1043 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1044}
1045
1046public override Vector3 GetLinearVelocity(BulletBody obj)
1047{
1048 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1049 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1050}
1051
1052public override Vector3 GetAngularVelocity(BulletBody obj)
1053{
1054 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1055 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1056}
1057
1058public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1059{
1060 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1061 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1062}
1063
1064public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1065{
1066 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1067 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1068}
1069
1070public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1071{
1072 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1073 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1074}
1075
1076public override void Translate(BulletBody obj, Vector3 trans)
1077{
1078 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1079 BSAPICPP.Translate2(bodyu.ptr, trans);
1080}
1081
1082public override void UpdateDeactivation(BulletBody obj, float timeStep)
1083{
1084 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1085 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1086}
1087
1088public override bool WantsSleeping(BulletBody obj)
1089{
1090 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1091 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1092}
1093
1094public override void SetAngularFactor(BulletBody obj, float factor)
1095{
1096 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1097 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1098}
1099
1100public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1101{
1102 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1103 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1104}
1105
1106public override Vector3 GetAngularFactor(BulletBody obj)
1107{
1108 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1109 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1110}
1111
1112public override bool IsInWorld(BulletWorld world, BulletBody obj)
1113{
1114 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1115 return BSAPICPP.IsInWorld2(bodyu.ptr);
1116}
1117
1118public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1119{
1120 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1121 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1122 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1123}
1124
1125public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1126{
1127 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1128 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1129 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1130}
1131
1132public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1133{
1134 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1135 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1136}
1137
1138public override int GetNumConstraintRefs(BulletBody obj)
1139{
1140 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1141 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1142}
1143
1144public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1145{
1146 BulletBodyUnman bodyu = body as BulletBodyUnman;
1147 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1148}
1149
1150// =====================================================================================
1151// btCollisionShape entries
1152
1153public override float GetAngularMotionDisc(BulletShape shape)
1154{
1155 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1156 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1157}
1158
1159public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1160{
1161 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1162 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1163}
1164
1165public override bool IsPolyhedral(BulletShape shape)
1166{
1167 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1168 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1169}
1170
1171public override bool IsConvex2d(BulletShape shape)
1172{
1173 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1174 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1175}
1176
1177public override bool IsConvex(BulletShape shape)
1178{
1179 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1180 return BSAPICPP.IsConvex2(shapeu.ptr);
1181}
1182
1183public override bool IsNonMoving(BulletShape shape)
1184{
1185 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1186 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1187}
1188
1189public override bool IsConcave(BulletShape shape)
1190{
1191 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1192 return BSAPICPP.IsConcave2(shapeu.ptr);
1193}
1194
1195public override bool IsCompound(BulletShape shape)
1196{
1197 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1198 return BSAPICPP.IsCompound2(shapeu.ptr);
1199}
1200
1201public override bool IsSoftBody(BulletShape shape)
1202{
1203 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1204 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1205}
1206
1207public override bool IsInfinite(BulletShape shape)
1208{
1209 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1210 return BSAPICPP.IsInfinite2(shapeu.ptr);
1211}
1212
1213public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1214{
1215 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1216 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1217}
1218
1219public override Vector3 GetLocalScaling(BulletShape shape)
1220{
1221 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1222 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1223}
1224
1225public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1226{
1227 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1228 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1229}
1230
1231public override int GetShapeType(BulletShape shape)
1232{
1233 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1234 return BSAPICPP.GetShapeType2(shapeu.ptr);
1235}
1236
1237public override void SetMargin(BulletShape shape, float val)
1238{
1239 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1240 BSAPICPP.SetMargin2(shapeu.ptr, val);
1241}
1242
1243public override float GetMargin(BulletShape shape)
1244{
1245 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1246 return BSAPICPP.GetMargin2(shapeu.ptr);
1247}
1248
1249// =====================================================================================
1250// Debugging
1251public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1252{
1253 BulletWorldUnman worldu = world as BulletWorldUnman;
1254 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1255 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1256}
1257
1258public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1259{
1260 BulletWorldUnman worldu = world as BulletWorldUnman;
1261 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1262 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1263}
1264
1265public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1266{
1267 BulletWorldUnman worldu = world as BulletWorldUnman;
1268 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1269 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1270}
1271
1272public override void DumpActivationInfo(BulletWorld world)
1273{
1274 BulletWorldUnman worldu = world as BulletWorldUnman;
1275 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1276}
1277
1278public override void DumpAllInfo(BulletWorld world)
1279{
1280 BulletWorldUnman worldu = world as BulletWorldUnman;
1281 BSAPICPP.DumpAllInfo2(worldu.ptr);
1282}
1283
1284public override void DumpPhysicsStatistics(BulletWorld world)
1285{
1286 BulletWorldUnman worldu = world as BulletWorldUnman;
1287 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1288}
1289public override void ResetBroadphasePool(BulletWorld world)
1290{
1291 BulletWorldUnman worldu = world as BulletWorldUnman;
1292 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1293}
1294public override void ResetConstraintSolver(BulletWorld world)
1295{
1296 BulletWorldUnman worldu = world as BulletWorldUnman;
1297 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1298}
1299
1300// =====================================================================================
1301// =====================================================================================
1302// =====================================================================================
1303// =====================================================================================
1304// =====================================================================================
1305// The actual interface to the unmanaged code
1306static class BSAPICPP
1307{
1308// ===============================================================================
1309// Link back to the managed code for outputting log messages
1310[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1311public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1312
1313// ===============================================================================
1314// Initialization and simulation
1315[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1316public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1317 int maxCollisions, IntPtr collisionArray,
1318 int maxUpdates, IntPtr updateArray,
1319 DebugLogCallback logRoutine);
1320
1321[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1322public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1323 out int updatedEntityCount, out int collidersCount);
1324
1325[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1326public static extern void Shutdown2(IntPtr sim);
1327
1328[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1329public static extern bool PushUpdate2(IntPtr obj);
1330
1331[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1332public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1333
1334// =====================================================================================
1335// Mesh, hull, shape and body creation helper routines
1336[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1337public static extern IntPtr CreateMeshShape2(IntPtr world,
1338 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1339 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1340
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern IntPtr CreateHullShape2(IntPtr world,
1343 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1344
1345[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1346public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1347
1348[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1349public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1350
1351[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1352public static extern bool IsNativeShape2(IntPtr shape);
1353
1354[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1355public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin);
1356
1357[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1358public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1359
1360[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1361public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1362
1363[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1364public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1365
1366[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1367public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1368
1369[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1370public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1371
1372[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1373public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1374
1375[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1376public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1377
1378[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1379public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1380
1381[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1382public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1383
1384[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1385public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1386
1387[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1388public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1389
1390[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1391public static extern int GetBodyType2(IntPtr obj);
1392
1393[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1394public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1395
1396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1397public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1398
1399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1400public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1401
1402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1403public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1404
1405// =====================================================================================
1406// Terrain creation and helper routines
1407[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1408public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1409
1410[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1411public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1412 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1413 float scaleFactor, float collisionMargin);
1414
1415// =====================================================================================
1416// Constraint creation and helper routines
1417[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1418public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1419 Vector3 frame1loc, Quaternion frame1rot,
1420 Vector3 frame2loc, Quaternion frame2rot,
1421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1422
1423[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1424public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1425 Vector3 joinPoint,
1426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1427
1428[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1429public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1430 Vector3 pivotinA, Vector3 pivotinB,
1431 Vector3 axisInA, Vector3 axisInB,
1432 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1433
1434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1435public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1436
1437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1438public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1439
1440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1441public static extern bool SetFrames2(IntPtr constrain,
1442 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1443
1444[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1445public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1446
1447[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1448public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1449
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1452
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1454public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1455
1456[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1457public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1458
1459[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1460public static extern bool CalculateTransforms2(IntPtr constrain);
1461
1462[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1463public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1464
1465[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1466public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1467
1468// =====================================================================================
1469// btCollisionWorld entries
1470[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1471public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1472
1473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1474public static extern void UpdateAabbs2(IntPtr world);
1475
1476[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1477public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1478
1479[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1480public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1481
1482// =====================================================================================
1483// btDynamicsWorld entries
1484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1485public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1486
1487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1488public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1489
1490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1491public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1492
1493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1494public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1495// =====================================================================================
1496// btCollisionObject entries
1497[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1498public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1499
1500[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1501public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1502
1503[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1504public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1505
1506[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1507public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1508
1509[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1510public static extern float GetContactProcessingThreshold2(IntPtr obj);
1511
1512[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1513public static extern bool IsStaticObject2(IntPtr obj);
1514
1515[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1516public static extern bool IsKinematicObject2(IntPtr obj);
1517
1518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1519public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1520
1521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1522public static extern bool HasContactResponse2(IntPtr obj);
1523
1524[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1525public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1526
1527[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1528public static extern IntPtr GetCollisionShape2(IntPtr obj);
1529
1530[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1531public static extern int GetActivationState2(IntPtr obj);
1532
1533[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1534public static extern void SetActivationState2(IntPtr obj, int state);
1535
1536[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1537public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1538
1539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1540public static extern float GetDeactivationTime2(IntPtr obj);
1541
1542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1543public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1544
1545[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1546public static extern void Activate2(IntPtr obj, bool forceActivation);
1547
1548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1549public static extern bool IsActive2(IntPtr obj);
1550
1551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1552public static extern void SetRestitution2(IntPtr obj, float val);
1553
1554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1555public static extern float GetRestitution2(IntPtr obj);
1556
1557[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1558public static extern void SetFriction2(IntPtr obj, float val);
1559
1560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1561public static extern float GetFriction2(IntPtr obj);
1562
1563 /* Haven't defined the type 'Transform'
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern Transform GetWorldTransform2(IntPtr obj);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1569 */
1570
1571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1572public static extern Vector3 GetPosition2(IntPtr obj);
1573
1574[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1575public static extern Quaternion GetOrientation2(IntPtr obj);
1576
1577[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1578public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1579
1580[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1581public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1582
1583[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1584public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1585
1586 /*
1587[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1588public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1589
1590[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1591public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1592 */
1593
1594[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1595public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1596
1597[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1598public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1599
1600[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1601public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1602
1603[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1604public static extern float GetHitFraction2(IntPtr obj);
1605
1606[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1607public static extern void SetHitFraction2(IntPtr obj, float val);
1608
1609[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1610public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1611
1612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1613public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1614
1615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1616public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1617
1618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1619public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1620
1621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1622public static extern float GetCcdMotionThreshold2(IntPtr obj);
1623
1624[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1625public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1626
1627[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1628public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1629
1630[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1631public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1632
1633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1634public static extern IntPtr GetUserPointer2(IntPtr obj);
1635
1636[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1637public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1638
1639// =====================================================================================
1640// btRigidBody entries
1641[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1642public static extern void ApplyGravity2(IntPtr obj);
1643
1644[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1645public static extern void SetGravity2(IntPtr obj, Vector3 val);
1646
1647[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1648public static extern Vector3 GetGravity2(IntPtr obj);
1649
1650[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1651public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1652
1653[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1654public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1655
1656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1657public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1658
1659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1660public static extern float GetLinearDamping2(IntPtr obj);
1661
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern float GetAngularDamping2(IntPtr obj);
1664
1665[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1666public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1667
1668[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1669public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1670
1671[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1672public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1673
1674[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1675public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1676
1677[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1678public static extern Vector3 GetLinearFactor2(IntPtr obj);
1679
1680[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1681public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1682
1683 /*
1684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1685public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1686 */
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1690
1691// Add a force to the object as if its mass is one.
1692[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1693public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1694
1695// Set the force being applied to the object as if its mass is one.
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1698
1699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1700public static extern Vector3 GetTotalForce2(IntPtr obj);
1701
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern Vector3 GetTotalTorque2(IntPtr obj);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1713
1714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1715public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1716
1717// Apply force at the given point. Will add torque to the object.
1718[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1719public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1720
1721// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1724
1725// Apply impulse to the object's torque. Force is scaled by object's mass.
1726[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1727public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1728
1729// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1730[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1731public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1732
1733[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1734public static extern void ClearForces2(IntPtr obj);
1735
1736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1737public static extern void ClearAllForces2(IntPtr obj);
1738
1739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1740public static extern void UpdateInertiaTensor2(IntPtr obj);
1741
1742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1743public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1744
1745 /*
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1748 */
1749
1750[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1751public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1752
1753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1754public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1755
1756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1757public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1758
1759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1760public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1761
1762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1763public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1764
1765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1766public static extern void Translate2(IntPtr obj, Vector3 trans);
1767
1768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1769public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1770
1771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1772public static extern bool WantsSleeping2(IntPtr obj);
1773
1774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1775public static extern void SetAngularFactor2(IntPtr obj, float factor);
1776
1777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1778public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1779
1780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1781public static extern Vector3 GetAngularFactor2(IntPtr obj);
1782
1783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1784public static extern bool IsInWorld2(IntPtr obj);
1785
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1788
1789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1790public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1791
1792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1793public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1794
1795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1796public static extern int GetNumConstraintRefs2(IntPtr obj);
1797
1798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1799public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1800
1801// =====================================================================================
1802// btCollisionShape entries
1803
1804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1805public static extern float GetAngularMotionDisc2(IntPtr shape);
1806
1807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1808public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1809
1810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1811public static extern bool IsPolyhedral2(IntPtr shape);
1812
1813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1814public static extern bool IsConvex2d2(IntPtr shape);
1815
1816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1817public static extern bool IsConvex2(IntPtr shape);
1818
1819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1820public static extern bool IsNonMoving2(IntPtr shape);
1821
1822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1823public static extern bool IsConcave2(IntPtr shape);
1824
1825[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1826public static extern bool IsCompound2(IntPtr shape);
1827
1828[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1829public static extern bool IsSoftBody2(IntPtr shape);
1830
1831[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1832public static extern bool IsInfinite2(IntPtr shape);
1833
1834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1835public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1836
1837[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1838public static extern Vector3 GetLocalScaling2(IntPtr shape);
1839
1840[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1841public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1842
1843[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1844public static extern int GetShapeType2(IntPtr shape);
1845
1846[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1847public static extern void SetMargin2(IntPtr shape, float val);
1848
1849[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1850public static extern float GetMargin2(IntPtr shape);
1851
1852// =====================================================================================
1853// Debugging
1854[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1855public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1856
1857[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1858public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1859
1860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1861public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1862
1863[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1864public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1865
1866[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1867public static extern void DumpActivationInfo2(IntPtr sim);
1868
1869[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1870public static extern void DumpAllInfo2(IntPtr sim);
1871
1872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1873public static extern void DumpPhysicsStatistics2(IntPtr sim);
1874
1875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1876public static extern void ResetBroadphasePool(IntPtr sim);
1877
1878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1879public static extern void ResetConstraintSolver(IntPtr sim);
1880
1881}
1882
1883}
1884
1885}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
new file mode 100755
index 0000000..b6ff52b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -0,0 +1,1598 @@
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.IO;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OpenMetaverse;
35
36using BulletXNA;
37using BulletXNA.LinearMath;
38using BulletXNA.BulletCollision;
39using BulletXNA.BulletDynamics;
40using BulletXNA.BulletCollision.CollisionDispatch;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSAPIXNA : BSAPITemplate
45{
46private sealed class BulletWorldXNA : BulletWorld
47{
48 public DiscreteDynamicsWorld world;
49 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
50 : base(id, physScene)
51 {
52 world = xx;
53 }
54}
55
56private sealed class BulletBodyXNA : BulletBody
57{
58 public CollisionObject body;
59 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
60
61 public BulletBodyXNA(uint id, CollisionObject xx)
62 : base(id)
63 {
64 body = xx;
65 }
66 public override bool HasPhysicalBody
67 {
68 get { return body != null; }
69 }
70 public override void Clear()
71 {
72 body = null;
73 }
74 public override string AddrString
75 {
76 get { return "XNARigidBody"; }
77 }
78}
79
80private sealed class BulletShapeXNA : BulletShape
81{
82 public CollisionShape shape;
83 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
84 : base()
85 {
86 shape = xx;
87 type = typ;
88 }
89 public override bool HasPhysicalShape
90 {
91 get { return shape != null; }
92 }
93 public override void Clear()
94 {
95 shape = null;
96 }
97 public override BulletShape Clone()
98 {
99 return new BulletShapeXNA(shape, type);
100 }
101 public override bool ReferenceSame(BulletShape other)
102 {
103 BulletShapeXNA otheru = other as BulletShapeXNA;
104 return (otheru != null) && (this.shape == otheru.shape);
105
106 }
107 public override string AddrString
108 {
109 get { return "XNACollisionShape"; }
110 }
111}
112private sealed class BulletConstraintXNA : BulletConstraint
113{
114 public TypedConstraint constrain;
115 public BulletConstraintXNA(TypedConstraint xx) : base()
116 {
117 constrain = xx;
118 }
119
120 public override void Clear()
121 {
122 constrain = null;
123 }
124 public override bool HasPhysicalConstraint { get { return constrain != null; } }
125
126 // Used for log messages for a unique display of the memory/object allocated to this instance
127 public override string AddrString
128 {
129 get { return "XNAConstraint"; }
130 }
131}
132
133 private static int m_collisionsThisFrame;
134 private BSScene PhysicsScene { get; set; }
135
136 public override string BulletEngineName { get { return "BulletXNA"; } }
137 public override string BulletEngineVersion { get; protected set; }
138
139 public BSAPIXNA(string paramName, BSScene physScene)
140 {
141 PhysicsScene = physScene;
142 }
143
144 /// <summary>
145 ///
146 /// </summary>
147 /// <param name="p"></param>
148 /// <param name="p_2"></param>
149 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
150 {
151 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
152 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
153 world.RemoveRigidBody(body);
154 return true;
155 }
156
157 public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
158 {
159 /* TODO */
160 return false;
161 }
162
163 public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
164 {
165 /* TODO */
166 return false;
167 }
168
169 public override void SetRestitution(BulletBody pBody, float pRestitution)
170 {
171 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
172 body.SetRestitution(pRestitution);
173 }
174
175 public override int GetShapeType(BulletShape pShape)
176 {
177 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
178 return (int)shape.GetShapeType();
179 }
180 public override void SetMargin(BulletShape pShape, float pMargin)
181 {
182 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
183 shape.SetMargin(pMargin);
184 }
185
186 public override float GetMargin(BulletShape pShape)
187 {
188 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
189 return shape.GetMargin();
190 }
191
192 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
193 {
194 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
195 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
196 shape.SetLocalScaling(ref vec);
197
198 }
199
200 public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold)
201 {
202 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
203 body.SetContactProcessingThreshold(contactprocessingthreshold);
204 }
205
206 public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold)
207 {
208 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
209 body.SetCcdMotionThreshold(pccdMotionThreashold);
210 }
211
212 public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius)
213 {
214 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
215 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
216 }
217
218 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
219 {
220 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
221 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
222 }
223
224 public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
225 {
226 CollisionObject body = ((BulletBodyXNA)pBody).body;
227 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
228 existingcollisionFlags |= pcollisionFlags;
229 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
230 return (CollisionFlags) (uint) existingcollisionFlags;
231 }
232
233 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
234 {
235 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
236 CollisionObject cbody = ((BulletBodyXNA)pBody).body;
237 RigidBody rbody = cbody as RigidBody;
238
239 // Bullet resets several variables when an object is added to the world. In particular,
240 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
241 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
242 IndexedMatrix origPos = cbody.GetWorldTransform();
243 if (rbody != null)
244 {
245 IndexedVector3 origGrav = rbody.GetGravity();
246 world.AddRigidBody(rbody);
247 rbody.SetGravity(origGrav);
248 }
249 else
250 {
251 world.AddCollisionObject(rbody);
252 }
253 cbody.SetWorldTransform(origPos);
254
255 pBody.ApplyCollisionMask(pWorld.physicsScene);
256
257 //if (body.GetBroadphaseHandle() != null)
258 // world.UpdateSingleAabb(body);
259 return true;
260 }
261
262 public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState)
263 {
264 CollisionObject body = ((BulletBodyXNA)pBody).body;
265 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
266 }
267
268 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody)
269 {
270 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
271 CollisionObject body = ((BulletBodyXNA)pBody).body;
272 world.UpdateSingleAabb(body);
273 }
274
275 public override void UpdateAabbs(BulletWorld world) { /* TODO */ }
276 public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; }
277 public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ }
278
279 public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask)
280 {
281 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
282 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
283 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
284 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
285 return false;
286 return true;
287 }
288
289 public override void ClearAllForces(BulletBody pBody)
290 {
291 CollisionObject body = ((BulletBodyXNA)pBody).body;
292 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
293 body.SetInterpolationLinearVelocity(ref zeroVector);
294 body.SetInterpolationAngularVelocity(ref zeroVector);
295 IndexedMatrix bodytransform = body.GetWorldTransform();
296
297 body.SetInterpolationWorldTransform(ref bodytransform);
298
299 if (body is RigidBody)
300 {
301 RigidBody rigidbody = body as RigidBody;
302 rigidbody.SetLinearVelocity(zeroVector);
303 rigidbody.SetAngularVelocity(zeroVector);
304 rigidbody.ClearForces();
305 }
306 }
307
308 public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3)
309 {
310 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
311 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
312 body.SetInterpolationAngularVelocity(ref vec);
313 }
314
315 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
316 {
317 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
318 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
319 body.SetAngularVelocity(ref vec);
320 }
321 public override Vector3 GetTotalForce(BulletBody pBody)
322 {
323 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
324 IndexedVector3 iv3 = body.GetTotalForce();
325 return new Vector3(iv3.X, iv3.Y, iv3.Z);
326 }
327 public override Vector3 GetTotalTorque(BulletBody pBody)
328 {
329 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
330 IndexedVector3 iv3 = body.GetTotalTorque();
331 return new Vector3(iv3.X, iv3.Y, iv3.Z);
332 }
333 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
334 {
335 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
336 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
337 return new Vector3(iv3.X, iv3.Y, iv3.Z);
338 }
339 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
340 {
341 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
342 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
343 body.SetInvInertiaDiagLocal(ref iv3);
344 }
345 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
346 {
347 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
348 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
349 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
350 body.ApplyForce(ref forceiv3, ref posiv3);
351 }
352 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
353 {
354 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
355 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
356 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
357 body.ApplyImpulse(ref impiv3, ref posiv3);
358 }
359
360 public override void ClearForces(BulletBody pBody)
361 {
362 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
363 body.ClearForces();
364 }
365
366 public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation)
367 {
368 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
369 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
370 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
371 _orientation.W);
372 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
373 mat._origin = vposition;
374 body.SetWorldTransform(mat);
375
376 }
377
378 public override Vector3 GetPosition(BulletBody pBody)
379 {
380 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
381 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
382 return new Vector3(pos.X, pos.Y, pos.Z);
383 }
384
385 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
386 {
387 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
388 IndexedVector3 inertia = IndexedVector3.Zero;
389 shape.CalculateLocalInertia(pphysMass, out inertia);
390 return new Vector3(inertia.X, inertia.Y, inertia.Z);
391 }
392
393 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
394 {
395 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
396 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
397 body.SetMassProps(pphysMass, inertia);
398 }
399
400
401 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
402 {
403 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
404 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
405 body.SetTotalForce(ref force);
406 }
407
408 public override void SetFriction(BulletBody pBody, float _currentFriction)
409 {
410 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
411 body.SetFriction(_currentFriction);
412 }
413
414 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
415 {
416 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
417 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
418 body.SetLinearVelocity(velocity);
419 }
420
421 public override void Activate(BulletBody pBody, bool pforceactivation)
422 {
423 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
424 body.Activate(pforceactivation);
425
426 }
427
428 public override Quaternion GetOrientation(BulletBody pBody)
429 {
430 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
431 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
432 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
433 }
434
435 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
436 {
437 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
438 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
439 existingcollisionFlags &= ~pcollisionFlags;
440 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
441 return (CollisionFlags)(uint)existingcollisionFlags;
442 }
443
444 public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; }
445
446 public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; }
447
448 public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; }
449
450 public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ }
451
452 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
453 {
454 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
455 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
456 body.SetGravity(gravity);
457 }
458
459 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
460 {
461 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
462 TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain;
463 world.RemoveConstraint(constraint);
464 return true;
465 }
466
467 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
468 {
469 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
470 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
471 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
472 constraint.SetLinearLowerLimit(lowlimit);
473 constraint.SetLinearUpperLimit(highlimit);
474 return true;
475 }
476
477 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
478 {
479 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
480 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
481 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
482 constraint.SetAngularLowerLimit(lowlimit);
483 constraint.SetAngularUpperLimit(highlimit);
484 return true;
485 }
486
487 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
488 {
489 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
490 constraint.SetOverrideNumSolverIterations((int)cnt);
491 }
492
493 public override bool CalculateTransforms(BulletConstraint pConstraint)
494 {
495 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
496 constraint.CalculateTransforms();
497 return true;
498 }
499
500 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
501 {
502 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
503 constraint.SetEnabled((p_2 == 0) ? false : true);
504 }
505
506
507 //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
508 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
509
510 {
511 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
512 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
513 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
514 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
515 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
516 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
517 frame1._origin = frame1v;
518
519 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
520 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
521 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
522 frame2._origin = frame1v;
523
524 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
525 puseLinearReferenceFrameA);
526 consttr.CalculateTransforms();
527 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
528
529 return new BulletConstraintXNA(consttr);
530 }
531
532
533 /// <summary>
534 ///
535 /// </summary>
536 /// <param name="pWorld"></param>
537 /// <param name="pBody1"></param>
538 /// <param name="pBody2"></param>
539 /// <param name="pjoinPoint"></param>
540 /// <param name="puseLinearReferenceFrameA"></param>
541 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
542 /// <returns></returns>
543 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
544 {
545 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
546 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
547 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
548 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
549 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
550
551 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
552 IndexedMatrix mat = IndexedMatrix.Identity;
553 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
554 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
555 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
556
557 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
558 consttr.CalculateTransforms();
559 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
560
561 return new BulletConstraintXNA(consttr);
562 }
563 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
564 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
565 {
566 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
567 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
568 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
569 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
570 frame1._origin = frame1v;
571
572 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
573 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
574 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
575 frame2._origin = frame1v;
576 constraint.SetFrames(ref frame1, ref frame2);
577 return true;
578 }
579
580 public override Vector3 GetLinearVelocity(BulletBody pBody)
581 {
582 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
583 IndexedVector3 iv3 = body.GetLinearVelocity();
584 return new Vector3(iv3.X, iv3.Y, iv3.Z);
585 }
586 public override Vector3 GetAngularVelocity(BulletBody pBody)
587 {
588 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
589 IndexedVector3 iv3 = body.GetAngularVelocity();
590 return new Vector3(iv3.X, iv3.Y, iv3.Z);
591 }
592 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
593 {
594 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
595 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
596 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
597 return new Vector3(iv3.X, iv3.Y, iv3.Z);
598 }
599 public override void Translate(BulletBody pBody, Vector3 trans)
600 {
601 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
602 }
603 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
604 {
605 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
606 body.UpdateDeactivation(timeStep);
607 }
608
609 public override bool WantsSleeping(BulletBody pBody)
610 {
611 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
612 return body.WantsSleeping();
613 }
614
615 public override void SetAngularFactor(BulletBody pBody, float factor)
616 {
617 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
618 body.SetAngularFactor(factor);
619 }
620
621 public override Vector3 GetAngularFactor(BulletBody pBody)
622 {
623 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
624 IndexedVector3 iv3 = body.GetAngularFactor();
625 return new Vector3(iv3.X, iv3.Y, iv3.Z);
626 }
627
628 public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody)
629 {
630 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
631 CollisionObject body = ((BulletBodyXNA)pBody).body;
632 return world.IsInWorld(body);
633 }
634
635 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
636 {
637 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
638 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
639 body.AddConstraintRef(constrain);
640 }
641
642 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
643 {
644 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
645 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
646 body.RemoveConstraintRef(constrain);
647 }
648
649 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
650 {
651 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
652 return new BulletConstraintXNA(body.GetConstraintRef(index));
653 }
654
655 public override int GetNumConstraintRefs(BulletBody pBody)
656 {
657 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
658 return body.GetNumConstraintRefs();
659 }
660
661 public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity)
662 {
663 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
664 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
665 body.SetInterpolationLinearVelocity(ref velocity);
666 }
667
668 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
669 {
670 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
671 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
672 return true;
673 }
674 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
675 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
676 {
677 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
678 constraint.SetBreakingImpulseThreshold(threshold);
679 return true;
680 }
681 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
682 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
683 {
684 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
685 float lineardamping = body.GetLinearDamping();
686 body.SetDamping(lineardamping, angularDamping);
687
688 }
689
690 public override void UpdateInertiaTensor(BulletBody pBody)
691 {
692 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
693 body.UpdateInertiaTensor();
694 }
695
696 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
697 {
698 CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
699 shape.RecalculateLocalAabb();
700 }
701
702 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
703 public override CollisionFlags GetCollisionFlags(BulletBody pBody)
704 {
705 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
706 uint flags = (uint)body.GetCollisionFlags();
707 return (CollisionFlags) flags;
708 }
709
710 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
711 {
712 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
713 body.SetDamping(pLinear, pAngular);
714 }
715 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
716 public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime)
717 {
718 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
719 body.SetDeactivationTime(pDeactivationTime);
720 }
721 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
722 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
723 {
724 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
725 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
726 }
727
728 public override CollisionObjectTypes GetBodyType(BulletBody pBody)
729 {
730 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
731 return (CollisionObjectTypes)(int) body.GetInternalType();
732 }
733
734 public override void ApplyGravity(BulletBody obj) { /* TODO */ }
735
736 public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; }
737
738 public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ }
739
740 public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; }
741
742 public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; }
743
744 public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; }
745
746 public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ }
747
748 public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; }
749
750 public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ }
751
752 public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ }
753
754 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
755 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
756 {
757 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
758 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
759 body.ApplyCentralForce(ref fSum);
760 }
761 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
762 {
763 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
764 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
765 body.ApplyCentralImpulse(ref fSum);
766 }
767 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
768 {
769 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
770 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
771 body.ApplyTorque(ref fSum);
772 }
773 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
774 {
775 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
776 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
777 body.ApplyTorqueImpulse(ref fSum);
778 }
779
780 public override void DestroyObject(BulletWorld p, BulletBody p_2)
781 {
782 //TODO:
783 }
784
785 public override void Shutdown(BulletWorld pWorld)
786 {
787 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
788 world.Cleanup();
789 }
790
791 public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id)
792 {
793 return null;
794 }
795
796 public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2)
797 {
798 //TODO:
799 return false;
800 }
801 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
802
803 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
804 {
805 CollisionWorld world = ((BulletWorldXNA)pWorld).world;
806 IndexedMatrix mat =
807 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
808 pRawOrientation.Z, pRawOrientation.W));
809 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
810 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
811 //UpdateSingleAabb(world, shape);
812 // TODO: Feed Update array into null
813 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
814
815 body.SetUserPointer(pLocalID);
816 return new BulletBodyXNA(pLocalID, body);
817 }
818
819
820 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
821 {
822
823 IndexedMatrix mat =
824 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
825 pRawOrientation.Z, pRawOrientation.W));
826 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
827
828 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
829
830 // TODO: Feed Update array into null
831 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
832 body.SetWorldTransform(mat);
833 body.SetUserPointer(pLocalID);
834 return new BulletBodyXNA(pLocalID, body);
835 }
836 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
837 public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags)
838 {
839 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
840 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
841 return (CollisionFlags)body.GetCollisionFlags();
842 }
843
844 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; }
845 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
846 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
847 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
848 public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; }
849 public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; }
850 public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; }
851 public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; }
852 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
853 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
854 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
855 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
856 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
857 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
858 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
859 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
860
861 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
862 public override void SetHitFraction(BulletBody pBody, float pHitFraction)
863 {
864 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
865 body.SetHitFraction(pHitFraction);
866 }
867 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
868 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
869 {
870 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
871 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
872 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
873 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
874 capsuleShapeZ.SetLocalScaling(ref scale);
875
876 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
877 }
878
879 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
880 int maxCollisions, ref CollisionDesc[] collisionArray,
881 int maxUpdates, ref EntityProperties[] updateArray
882 )
883 {
884 /* TODO */
885 return new BulletWorldXNA(1, null, null);
886 }
887
888 private static object Initialize2(Vector3 worldExtent,
889 ConfigurationParameters[] o,
890 int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray,
891 int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray,
892 object mDebugLogCallbackHandle)
893 {
894 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
895
896 p.angularDamping = o[0].XangularDamping;
897 p.defaultFriction = o[0].defaultFriction;
898 p.defaultFriction = o[0].defaultFriction;
899 p.defaultDensity = o[0].defaultDensity;
900 p.defaultRestitution = o[0].defaultRestitution;
901 p.collisionMargin = o[0].collisionMargin;
902 p.gravity = o[0].gravity;
903
904 p.linearDamping = o[0].XlinearDamping;
905 p.angularDamping = o[0].XangularDamping;
906 p.deactivationTime = o[0].XdeactivationTime;
907 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
908 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
909 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
910 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
911 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
912
913 p.terrainImplementation = o[0].XterrainImplementation;
914 p.terrainFriction = o[0].XterrainFriction;
915
916 p.terrainHitFraction = o[0].XterrainHitFraction;
917 p.terrainRestitution = o[0].XterrainRestitution;
918 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
919
920 p.avatarFriction = o[0].XavatarFriction;
921 p.avatarStandingFriction = o[0].XavatarStandingFriction;
922 p.avatarDensity = o[0].XavatarDensity;
923 p.avatarRestitution = o[0].XavatarRestitution;
924 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
925 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
926 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
927 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
928
929 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
930
931 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
932 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
933 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
934 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
935 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
936 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
937 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
938 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
939
940 p.linksetImplementation = o[0].XlinksetImplementation;
941 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
942 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
943 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
944 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
945 p.linkConstraintERP = o[0].XlinkConstraintERP;
946 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
947 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
948 p.physicsLoggingFrames = o[0].XphysicsLoggingFrames;
949 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
950
951 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
952 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
953
954
955 if (p.maxPersistantManifoldPoolSize > 0)
956 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
957 if (p.shouldDisableContactPoolDynamicAllocation !=0)
958 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
959 //if (p.maxCollisionAlgorithmPoolSize >0 )
960
961 DbvtBroadphase m_broadphase = new DbvtBroadphase();
962 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
963 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
964
965 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
966 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
967
968 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
969
970 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
971 world.UpdatedObjects = updateArray;
972 world.UpdatedCollisions = collisionArray;
973 world.WorldSettings.Params = p;
974 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
975 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
976 if (p.shouldRandomizeSolverOrder != 0)
977 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
978
979 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
980 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
981
982 if (p.shouldEnableFrictionCaching != 0)
983 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
984
985 if (p.numberOfSolverIterations > 0)
986 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
987
988
989 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
990 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
991 world.GetSolverInfo().m_globalCfm = 0.0f;
992 world.GetSolverInfo().m_tau = 0.6f;
993 world.GetSolverInfo().m_friction = 0.3f;
994 world.GetSolverInfo().m_maxErrorReduction = 20f;
995 world.GetSolverInfo().m_numIterations = 10;
996 world.GetSolverInfo().m_erp = 0.2f;
997 world.GetSolverInfo().m_erp2 = 0.1f;
998 world.GetSolverInfo().m_sor = 1.0f;
999 world.GetSolverInfo().m_splitImpulse = false;
1000 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1001 world.GetSolverInfo().m_linearSlop = 0.0f;
1002 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1003 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1004 world.SetForceUpdateAllAabbs(true);
1005
1006
1007 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1008
1009 return world;
1010 }
1011 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1012 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1013 {
1014 Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
1015 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1016 {
1017 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1018 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1019 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1020 }
1021 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1022 {
1023 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1024 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1025 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1026 }
1027 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1028 {
1029 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1030 }
1031 return true;
1032 }
1033
1034 public override bool PushUpdate(BulletBody pCollisionObject)
1035 {
1036 bool ret = false;
1037 RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody;
1038 if (rb != null)
1039 {
1040 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1041 if (sms != null)
1042 {
1043 IndexedMatrix wt = IndexedMatrix.Identity;
1044 sms.GetWorldTransform(out wt);
1045 sms.SetWorldTransform(ref wt, true);
1046 ret = true;
1047 }
1048 }
1049 return ret;
1050
1051 }
1052
1053 public override float GetAngularMotionDisc(BulletShape pShape)
1054 {
1055 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1056 return shape.GetAngularMotionDisc();
1057 }
1058 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1059 {
1060 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1061 return shape.GetContactBreakingThreshold(defaultFactor);
1062 }
1063 public override bool IsCompound(BulletShape pShape)
1064 {
1065 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1066 return shape.IsCompound();
1067 }
1068 public override bool IsSoftBody(BulletShape pShape)
1069 {
1070 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1071 return shape.IsSoftBody();
1072 }
1073 public override bool IsPolyhedral(BulletShape pShape)
1074 {
1075 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1076 return shape.IsPolyhedral();
1077 }
1078 public override bool IsConvex2d(BulletShape pShape)
1079 {
1080 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1081 return shape.IsConvex2d();
1082 }
1083 public override bool IsConvex(BulletShape pShape)
1084 {
1085 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1086 return shape.IsConvex();
1087 }
1088 public override bool IsNonMoving(BulletShape pShape)
1089 {
1090 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1091 return shape.IsNonMoving();
1092 }
1093 public override bool IsConcave(BulletShape pShape)
1094 {
1095 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1096 return shape.IsConcave();
1097 }
1098 public override bool IsInfinite(BulletShape pShape)
1099 {
1100 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1101 return shape.IsInfinite();
1102 }
1103 public override bool IsNativeShape(BulletShape pShape)
1104 {
1105 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1106 bool ret;
1107 switch (shape.GetShapeType())
1108 {
1109 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1110 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1111 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1112 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1113 ret = true;
1114 break;
1115 default:
1116 ret = false;
1117 break;
1118 }
1119 return ret;
1120 }
1121
1122 public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ }
1123
1124 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1125 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1126 {
1127 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1128 IndexedMatrix bodyTransform = new IndexedMatrix();
1129 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1130 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1131 GhostObject gObj = new PairCachingGhostObject();
1132 gObj.SetWorldTransform(bodyTransform);
1133 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1134 gObj.SetCollisionShape(shape);
1135 gObj.SetUserPointer(pLocalID);
1136 // TODO: Add to Special CollisionObjects!
1137 return new BulletBodyXNA(pLocalID, gObj);
1138 }
1139
1140 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape)
1141 {
1142 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1143 CollisionObject obj = ((BulletBodyXNA)pObj).body;
1144 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1145 obj.SetCollisionShape(shape);
1146
1147 }
1148 public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; }
1149
1150 //(PhysicsScene.World.ptr, nativeShapeData)
1151 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1152 {
1153 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1154 CollisionShape shape = null;
1155 switch (pShapeData.Type)
1156 {
1157 case BSPhysicsShapeType.SHAPE_BOX:
1158 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1159 break;
1160 case BSPhysicsShapeType.SHAPE_CONE:
1161 shape = new ConeShapeZ(0.5f, 1.0f);
1162 break;
1163 case BSPhysicsShapeType.SHAPE_CYLINDER:
1164 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1165 break;
1166 case BSPhysicsShapeType.SHAPE_SPHERE:
1167 shape = new SphereShape(0.5f);
1168 break;
1169
1170 }
1171 if (shape != null)
1172 {
1173 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1174 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1175 shape.SetLocalScaling(ref scaling);
1176
1177 }
1178 return new BulletShapeXNA(shape, pShapeData.Type);
1179 }
1180 //PhysicsScene.World.ptr, false
1181 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1182 {
1183 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1184 }
1185
1186 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1187 {
1188 CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
1189 return compoundshape.GetNumChildShapes();
1190 }
1191 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1192 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1193 {
1194 IndexedMatrix relativeTransform = new IndexedMatrix();
1195 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1196 CollisionShape addshape = ((BulletShapeXNA)paddShape).shape;
1197
1198 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1199 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1200 compoundshape.AddChildShape(ref relativeTransform, addshape);
1201
1202 }
1203
1204 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1205 {
1206 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1207 CollisionShape ret = null;
1208 ret = compoundshape.GetChildShape(pii);
1209 compoundshape.RemoveChildShapeByIndex(pii);
1210 return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN);
1211 }
1212
1213 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; }
1214 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1215 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1216
1217 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1218 {
1219 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1220 m_planeshape.SetMargin(pcollisionMargin);
1221 m_planeshape.SetUserPointer(pLocalId);
1222 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1223 }
1224
1225 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1226 {
1227 HingeConstraint constrain = null;
1228 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1229 RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody;
1230 RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody;
1231 if (rb1 != null && rb2 != null)
1232 {
1233 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1234 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1235 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1236 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1237 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1238 }
1239 return new BulletConstraintXNA(constrain);
1240 }
1241
1242 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1243 {
1244 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1245 CompoundShape compoundshape = new CompoundShape(false);
1246
1247 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1248 int ii = 1;
1249
1250 for (int i = 0; i < pHullCount; i++)
1251 {
1252 int vertexCount = (int) pConvHulls[ii];
1253
1254 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1255 IndexedMatrix childTrans = IndexedMatrix.Identity;
1256 childTrans._origin = centroid;
1257
1258 List<IndexedVector3> virts = new List<IndexedVector3>();
1259 int ender = ((ii + 4) + (vertexCount*3));
1260 for (int iii = ii + 4; iii < ender; iii+=3)
1261 {
1262
1263 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1264 }
1265 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1266 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1267 compoundshape.AddChildShape(ref childTrans, convexShape);
1268 ii += (vertexCount*3 + 4);
1269 }
1270
1271 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1272 }
1273
1274 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; }
1275
1276 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1277 {
1278 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1279
1280 for (int iter = 0; iter < pVerticesCount; iter++)
1281 {
1282 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1283 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1284 }
1285
1286 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1287 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1288 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1289 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1290 IndexedMesh mesh = new IndexedMesh();
1291 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1292 mesh.m_numTriangles = pIndicesCount/3;
1293 mesh.m_numVertices = pVerticesCount;
1294 mesh.m_triangleIndexBase = indicesarr;
1295 mesh.m_vertexBase = vertices;
1296 mesh.m_vertexStride = 3;
1297 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1298 mesh.m_triangleIndexStride = 3;
1299
1300 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1301 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1302 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1303 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1304 // world.UpdateSingleAabb(meshShape);
1305 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1306
1307 }
1308 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1309 {
1310
1311 String fileName = "objTest3.raw";
1312 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1313 StreamWriter sw = new StreamWriter(completePath);
1314 IndexedMesh mesh = new IndexedMesh();
1315
1316 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1317 mesh.m_numTriangles = pIndicesCount / 3;
1318 mesh.m_numVertices = pVerticesCount;
1319 mesh.m_triangleIndexBase = indices;
1320 mesh.m_vertexBase = vertices;
1321 mesh.m_vertexStride = 3;
1322 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1323 mesh.m_triangleIndexStride = 3;
1324
1325 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1326 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1327
1328
1329
1330 for (int i = 0; i < pVerticesCount; i++)
1331 {
1332
1333 string s = vertices[indices[i * 3]].ToString("0.0000");
1334 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1335 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1336
1337 sw.Write(s + "\n");
1338 }
1339
1340 sw.Close();
1341 }
1342 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1343 {
1344
1345 String fileName = "objTest6.raw";
1346 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1347 StreamWriter sw = new StreamWriter(completePath);
1348 IndexedMesh mesh = new IndexedMesh();
1349
1350 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1351 mesh.m_numTriangles = pIndicesCount / 3;
1352 mesh.m_numVertices = pVerticesCount;
1353 mesh.m_triangleIndexBase = indices;
1354 mesh.m_vertexBase = vertices;
1355 mesh.m_vertexStride = 3;
1356 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1357 mesh.m_triangleIndexStride = 3;
1358
1359 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1360 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1361
1362
1363 sw.WriteLine("Indices");
1364 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1365 for (int iter = 0; iter < indices.Length; iter++)
1366 {
1367 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1368 }
1369 sw.WriteLine("VerticesFloats");
1370 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1371 for (int iter = 0; iter < vertices.Length; iter++)
1372 {
1373 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1374 }
1375
1376 // for (int i = 0; i < pVerticesCount; i++)
1377 // {
1378 //
1379 // string s = vertices[indices[i * 3]].ToString("0.0000");
1380 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1381 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1382 //
1383 // sw.Write(s + "\n");
1384 //}
1385
1386 sw.Close();
1387 }
1388
1389 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1390 float scaleFactor, float collisionMargin)
1391 {
1392 const int upAxis = 2;
1393 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1394 heightMap, scaleFactor,
1395 minHeight, maxHeight, upAxis,
1396 false);
1397 terrainShape.SetMargin(collisionMargin + 0.5f);
1398 terrainShape.SetUseDiamondSubdivision(true);
1399 terrainShape.SetUserPointer(id);
1400 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1401 }
1402
1403 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1404 {
1405 TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain;
1406 bool onOff = ponOff != 0;
1407 bool ret = false;
1408
1409 switch (tconstrain.GetConstraintType())
1410 {
1411 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1412 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1413 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1414 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1415 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1416 ret = true;
1417 break;
1418 }
1419
1420
1421 return ret;
1422
1423 }
1424
1425 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1426 out int updatedEntityCount, out int collidersCount)
1427 {
1428 /* TODO */
1429 updatedEntityCount = 0;
1430 collidersCount = 0;
1431 return 1;
1432 }
1433
1434 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1435 out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities,
1436 out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1437 {
1438 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1439 out collidersCount, out colliders);
1440 return epic;
1441 }
1442
1443 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders)
1444 {
1445 int numSimSteps = 0;
1446
1447
1448 //if (updatedEntities is null)
1449 // updatedEntities = new List<BulletXNA.EntityProperties>();
1450
1451 //if (colliders is null)
1452 // colliders = new List<BulletXNA.CollisionDesc>();
1453
1454
1455 if (pWorld is BulletWorldXNA)
1456 {
1457 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1458
1459 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1460 int updates = 0;
1461
1462 updatedEntityCount = world.UpdatedObjects.Count;
1463 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1464 updatedEntityCount = updatedEntities.Count;
1465 world.UpdatedObjects.Clear();
1466
1467
1468 collidersCount = world.UpdatedCollisions.Count;
1469 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1470
1471 world.UpdatedCollisions.Clear();
1472 m_collisionsThisFrame = 0;
1473 int numManifolds = world.GetDispatcher().GetNumManifolds();
1474 for (int j = 0; j < numManifolds; j++)
1475 {
1476 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1477 int numContacts = contactManifold.GetNumContacts();
1478 if (numContacts == 0)
1479 continue;
1480
1481 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1482 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1483
1484 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1485 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1486 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1487
1488 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1489 m_collisionsThisFrame ++;
1490 if (m_collisionsThisFrame >= 9999999)
1491 break;
1492
1493
1494 }
1495
1496
1497 }
1498 else
1499 {
1500 //if (updatedEntities is null)
1501 updatedEntities = new List<BulletXNA.EntityProperties>();
1502 updatedEntityCount = 0;
1503 //if (colliders is null)
1504 colliders = new List<BulletXNA.CollisionDesc>();
1505 collidersCount = 0;
1506 }
1507 return numSimSteps;
1508 }
1509
1510 private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1511 {
1512
1513 IndexedVector3 contactNormal = norm;
1514 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1515 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1516 {
1517 return;
1518 }
1519 uint idA = (uint)objA.GetUserPointer();
1520 uint idB = (uint)objB.GetUserPointer();
1521 if (idA > idB)
1522 {
1523 uint temp = idA;
1524 idA = idB;
1525 idB = temp;
1526 contactNormal = -contactNormal;
1527 }
1528
1529 ulong collisionID = ((ulong) idA << 32) | idB;
1530
1531 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1532 {
1533 aID = idA,
1534 bID = idB,
1535 point = contact,
1536 normal = contactNormal
1537 };
1538 world.UpdatedCollisions.Add(cDesc);
1539 m_collisionsThisFrame++;
1540
1541
1542 }
1543 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody)
1544 {
1545 EntityProperties ent = new EntityProperties();
1546 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1547 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
1548 IndexedMatrix transform = body.GetWorldTransform();
1549 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1550 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1551 IndexedQuaternion rotation = transform.GetRotation();
1552 ent.Acceleration = Vector3.Zero;
1553 ent.ID = (uint)body.GetUserPointer();
1554 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1555 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1556 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1557 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1558 return ent;
1559 }
1560
1561 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; }
1562
1563 public override Vector3 GetLocalScaling(BulletShape pShape)
1564 {
1565 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1566 IndexedVector3 scale = shape.GetLocalScaling();
1567 return new Vector3(scale.X,scale.Y,scale.Z);
1568 }
1569
1570 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1571 {
1572 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1573 if (world != null)
1574 {
1575 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1576 {
1577 CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body;
1578
1579 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1580 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1581 using (
1582 ClosestNotMeRayResultCallback rayCallback =
1583 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
1584 )
1585 {
1586 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1587 if (rayCallback.HasHit())
1588 {
1589 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1590 }
1591 return rayCallback.HasHit();
1592 }
1593 }
1594 }
1595 return false;
1596 }
1597}
1598}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
new file mode 100644
index 0000000..bc163eb
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -0,0 +1,668 @@
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;
29using System.Runtime.InteropServices;
30using System.Security;
31using System.Text;
32using OpenMetaverse;
33
34namespace OpenSim.Region.Physics.BulletSPlugin {
35
36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int
38{
39 POINT2POINT_CONSTRAINT_TYPE = 3,
40 HINGE_CONSTRAINT_TYPE,
41 CONETWIST_CONSTRAINT_TYPE,
42 D6_CONSTRAINT_TYPE,
43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_CONSTRAINT_TYPE
47}
48
49// ===============================================================================
50[StructLayout(LayoutKind.Sequential)]
51public struct ConvexHull
52{
53 Vector3 Offset;
54 int VertexCount;
55 Vector3[] Vertices;
56}
57public enum BSPhysicsShapeType
58{
59 SHAPE_UNKNOWN = 0,
60 SHAPE_CAPSULE = 1,
61 SHAPE_BOX = 2,
62 SHAPE_CONE = 3,
63 SHAPE_CYLINDER = 4,
64 SHAPE_SPHERE = 5,
65 SHAPE_MESH = 6,
66 SHAPE_HULL = 7,
67 // following defined by BulletSim
68 SHAPE_GROUNDPLANE = 20,
69 SHAPE_TERRAIN = 21,
70 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24,
73};
74
75// The native shapes have predefined shape hash keys
76public enum FixedShapeKey : ulong
77{
78 KEY_NONE = 0,
79 KEY_BOX = 1,
80 KEY_SPHERE = 2,
81 KEY_CONE = 3,
82 KEY_CYLINDER = 4,
83 KEY_CAPSULE = 5,
84 KEY_AVATAR = 6,
85}
86
87[StructLayout(LayoutKind.Sequential)]
88public struct ShapeData
89{
90 public uint ID;
91 public BSPhysicsShapeType Type;
92 public Vector3 Position;
93 public Quaternion Rotation;
94 public Vector3 Velocity;
95 public Vector3 Scale;
96 public float Mass;
97 public float Buoyancy;
98 public System.UInt64 HullKey;
99 public System.UInt64 MeshKey;
100 public float Friction;
101 public float Restitution;
102 public float Collidable; // true of things bump into this
103 public float Static; // true if a static object. Otherwise gravity, etc.
104 public float Solid; // true if object cannot be passed through
105 public Vector3 Size;
106
107 // note that bools are passed as floats since bool size changes by language and architecture
108 public const float numericTrue = 1f;
109 public const float numericFalse = 0f;
110}
111[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit
113{
114 public uint ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public uint ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public uint aID;
130 public uint bID;
131 public Vector3 point;
132 public Vector3 normal;
133}
134[StructLayout(LayoutKind.Sequential)]
135public struct EntityProperties
136{
137 public uint ID;
138 public Vector3 Position;
139 public Quaternion Rotation;
140 public Vector3 Velocity;
141 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity;
143}
144
145// Format of this structure must match the definition in the C++ code
146// NOTE: adding the X causes compile breaks if used. These are unused symbols
147// that can be removed from both here and the unmanaged definition of this structure.
148[StructLayout(LayoutKind.Sequential)]
149public struct ConfigurationParameters
150{
151 public float defaultFriction;
152 public float defaultDensity;
153 public float defaultRestitution;
154 public float collisionMargin;
155 public float gravity;
156
157 public float XlinearDamping;
158 public float XangularDamping;
159 public float XdeactivationTime;
160 public float XlinearSleepingThreshold;
161 public float XangularSleepingThreshold;
162 public float XccdMotionThreshold;
163 public float XccdSweptSphereRadius;
164 public float XcontactProcessingThreshold;
165
166 public float XterrainImplementation;
167 public float XterrainFriction;
168 public float XterrainHitFraction;
169 public float XterrainRestitution;
170 public float XterrainCollisionMargin;
171
172 public float XavatarFriction;
173 public float XavatarStandingFriction;
174 public float XavatarDensity;
175 public float XavatarRestitution;
176 public float XavatarCapsuleWidth;
177 public float XavatarCapsuleDepth;
178 public float XavatarCapsuleHeight;
179 public float XavatarContactProcessingThreshold;
180
181 public float XvehicleAngularDamping;
182
183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation;
186 public float shouldForceUpdateAllAabbs;
187 public float shouldRandomizeSolverOrder;
188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations;
191
192 public float XlinksetImplementation;
193 public float XlinkConstraintUseFrameOffset;
194 public float XlinkConstraintEnableTransMotor;
195 public float XlinkConstraintTransMotorMaxVel;
196 public float XlinkConstraintTransMotorMaxForce;
197 public float XlinkConstraintERP;
198 public float XlinkConstraintCFM;
199 public float XlinkConstraintSolverIterations;
200
201 public float XphysicsLoggingFrames;
202
203 public const float numericTrue = 1f;
204 public const float numericFalse = 0f;
205}
206
207
208// The states a bullet collision object can have
209public enum ActivationState : uint
210{
211 ACTIVE_TAG = 1,
212 ISLAND_SLEEPING,
213 WANTS_DEACTIVATION,
214 DISABLE_DEACTIVATION,
215 DISABLE_SIMULATION,
216}
217
218public enum CollisionObjectTypes : int
219{
220 CO_COLLISION_OBJECT = 1 << 0,
221 CO_RIGID_BODY = 1 << 1,
222 CO_GHOST_OBJECT = 1 << 2,
223 CO_SOFT_BODY = 1 << 3,
224 CO_HF_FLUID = 1 << 4,
225 CO_USER_TYPE = 1 << 5,
226}
227
228// Values used by Bullet and BulletSim to control object properties.
229// Bullet's "CollisionFlags" has more to do with operations on the
230// object (if collisions happen, if gravity effects it, ...).
231public enum CollisionFlags : uint
232{
233 CF_STATIC_OBJECT = 1 << 0,
234 CF_KINEMATIC_OBJECT = 1 << 1,
235 CF_NO_CONTACT_RESPONSE = 1 << 2,
236 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
237 CF_CHARACTER_OBJECT = 1 << 4,
238 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
239 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
240 // Following used by BulletSim to control collisions and updates
241 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
242 BS_FLOATS_ON_WATER = 1 << 11,
243 BS_VEHICLE_COLLISIONS = 1 << 12,
244 BS_NONE = 0,
245 BS_ALL = 0xFFFFFFFF
246};
247
248// Values f collisions groups and masks
249public enum CollisionFilterGroups : uint
250{
251 // Don't use the bit definitions!! Define the use in a
252 // filter/mask definition below. This way collision interactions
253 // are more easily found and debugged.
254 BNoneGroup = 0,
255 BDefaultGroup = 1 << 0, // 0001
256 BStaticGroup = 1 << 1, // 0002
257 BKinematicGroup = 1 << 2, // 0004
258 BDebrisGroup = 1 << 3, // 0008
259 BSensorTrigger = 1 << 4, // 0010
260 BCharacterGroup = 1 << 5, // 0020
261 BAllGroup = 0x000FFFFF,
262 // Filter groups defined by BulletSim
263 BGroundPlaneGroup = 1 << 10, // 0400
264 BTerrainGroup = 1 << 11, // 0800
265 BRaycastGroup = 1 << 12, // 1000
266 BSolidGroup = 1 << 13, // 2000
267 // BLinksetGroup = xx // a linkset proper is either static or dynamic
268 BLinksetChildGroup = 1 << 14, // 4000
269};
270
271// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
272// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
273public enum ConstraintParams : int
274{
275 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
276 BT_CONSTRAINT_STOP_ERP,
277 BT_CONSTRAINT_CFM,
278 BT_CONSTRAINT_STOP_CFM,
279};
280public enum ConstraintParamAxis : int
281{
282 AXIS_LINEAR_X = 0,
283 AXIS_LINEAR_Y,
284 AXIS_LINEAR_Z,
285 AXIS_ANGULAR_X,
286 AXIS_ANGULAR_Y,
287 AXIS_ANGULAR_Z,
288 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
289 AXIS_ANGULAR_ALL,
290 AXIS_ALL
291};
292
293public abstract class BSAPITemplate
294{
295// Returns the name of the underlying Bullet engine
296public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;}
298
299// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
301 int maxCollisions, ref CollisionDesc[] collisionArray,
302 int maxUpdates, ref EntityProperties[] updateArray
303 );
304
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
306 out int updatedEntityCount, out int collidersCount);
307
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value);
309
310public abstract void Shutdown(BulletWorld sim);
311
312public abstract bool PushUpdate(BulletBody obj);
313
314// =====================================================================================
315// Mesh, hull, shape and body creation helper routines
316public abstract BulletShape CreateMeshShape(BulletWorld world,
317 int indicesCount, int[] indices,
318 int verticesCount, float[] vertices );
319
320public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls);
322
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
324
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326
327public abstract bool IsNativeShape(BulletShape shape);
328
329public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
330
331public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
332
333public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
334
335public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
336
337public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
338
339public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
340
341public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
342
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344
345public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
346
347public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
348
349public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id);
350
351public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
352
353public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
354
355public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
356
357public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot);
358
359public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
360
361public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
362
363// =====================================================================================
364public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin);
365
366public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
367 float scaleFactor, float collisionMargin);
368
369// =====================================================================================
370// Constraint creation and helper routines
371public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
372 Vector3 frame1loc, Quaternion frame1rot,
373 Vector3 frame2loc, Quaternion frame2rot,
374 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
375
376public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
377 Vector3 joinPoint,
378 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
379
380public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
381 Vector3 pivotinA, Vector3 pivotinB,
382 Vector3 axisInA, Vector3 axisInB,
383 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
384
385public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
386
387public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
388
389public abstract bool SetFrames(BulletConstraint constrain,
390 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
391
392public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
393
394public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
395
396public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
397
398public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
399
400public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
401
402public abstract bool CalculateTransforms(BulletConstraint constrain);
403
404public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
405
406public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
407
408// =====================================================================================
409// btCollisionWorld entries
410public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
411
412public abstract void UpdateAabbs(BulletWorld world);
413
414public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
415
416public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
417
418// =====================================================================================
419// btDynamicsWorld entries
420// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
421public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
422
423public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
424
425public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
426
427public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
428// =====================================================================================
429// btCollisionObject entries
430public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
431
432public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
433
434public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
435
436public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
437
438public abstract float GetContactProcessingThreshold(BulletBody obj);
439
440public abstract bool IsStaticObject(BulletBody obj);
441
442public abstract bool IsKinematicObject(BulletBody obj);
443
444public abstract bool IsStaticOrKinematicObject(BulletBody obj);
445
446public abstract bool HasContactResponse(BulletBody obj);
447
448public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
449
450public abstract BulletShape GetCollisionShape(BulletBody obj);
451
452public abstract int GetActivationState(BulletBody obj);
453
454public abstract void SetActivationState(BulletBody obj, int state);
455
456public abstract void SetDeactivationTime(BulletBody obj, float dtime);
457
458public abstract float GetDeactivationTime(BulletBody obj);
459
460public abstract void ForceActivationState(BulletBody obj, ActivationState state);
461
462public abstract void Activate(BulletBody obj, bool forceActivation);
463
464public abstract bool IsActive(BulletBody obj);
465
466public abstract void SetRestitution(BulletBody obj, float val);
467
468public abstract float GetRestitution(BulletBody obj);
469
470public abstract void SetFriction(BulletBody obj, float val);
471
472public abstract float GetFriction(BulletBody obj);
473
474public abstract Vector3 GetPosition(BulletBody obj);
475
476public abstract Quaternion GetOrientation(BulletBody obj);
477
478public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
479
480// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
481
482// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
483
484public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
485
486public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
487
488public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
489
490public abstract float GetHitFraction(BulletBody obj);
491
492public abstract void SetHitFraction(BulletBody obj, float val);
493
494public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
495
496public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
497
498public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
499
500public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
501
502public abstract float GetCcdMotionThreshold(BulletBody obj);
503
504public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
505
506public abstract float GetCcdSweptSphereRadius(BulletBody obj);
507
508public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
509
510public abstract IntPtr GetUserPointer(BulletBody obj);
511
512public abstract void SetUserPointer(BulletBody obj, IntPtr val);
513
514// =====================================================================================
515// btRigidBody entries
516public abstract void ApplyGravity(BulletBody obj);
517
518public abstract void SetGravity(BulletBody obj, Vector3 val);
519
520public abstract Vector3 GetGravity(BulletBody obj);
521
522public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
523
524public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
525
526public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
527
528public abstract float GetLinearDamping(BulletBody obj);
529
530public abstract float GetAngularDamping(BulletBody obj);
531
532public abstract float GetLinearSleepingThreshold(BulletBody obj);
533
534public abstract void ApplyDamping(BulletBody obj, float timeStep);
535
536public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
537
538public abstract Vector3 GetLinearFactor(BulletBody obj);
539
540public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
541
542public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
543
544// Add a force to the object as if its mass is one.
545public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
546
547// Set the force being applied to the object as if its mass is one.
548public abstract void SetObjectForce(BulletBody obj, Vector3 force);
549
550public abstract Vector3 GetTotalForce(BulletBody obj);
551
552public abstract Vector3 GetTotalTorque(BulletBody obj);
553
554public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
555
556public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
557
558public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
559
560public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
561
562// Apply force at the given point. Will add torque to the object.
563public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
564
565// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
566public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
567
568// Apply impulse to the object's torque. Force is scaled by object's mass.
569public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
570
571// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
572public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
573
574public abstract void ClearForces(BulletBody obj);
575
576public abstract void ClearAllForces(BulletBody obj);
577
578public abstract void UpdateInertiaTensor(BulletBody obj);
579
580public abstract Vector3 GetLinearVelocity(BulletBody obj);
581
582public abstract Vector3 GetAngularVelocity(BulletBody obj);
583
584public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
585
586public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
587
588public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
589
590public abstract void Translate(BulletBody obj, Vector3 trans);
591
592public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
593
594public abstract bool WantsSleeping(BulletBody obj);
595
596public abstract void SetAngularFactor(BulletBody obj, float factor);
597
598public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
599
600public abstract Vector3 GetAngularFactor(BulletBody obj);
601
602public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
603
604public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
605
606public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
607
608public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
609
610public abstract int GetNumConstraintRefs(BulletBody obj);
611
612public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask);
613
614// =====================================================================================
615// btCollisionShape entries
616
617public abstract float GetAngularMotionDisc(BulletShape shape);
618
619public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
620
621public abstract bool IsPolyhedral(BulletShape shape);
622
623public abstract bool IsConvex2d(BulletShape shape);
624
625public abstract bool IsConvex(BulletShape shape);
626
627public abstract bool IsNonMoving(BulletShape shape);
628
629public abstract bool IsConcave(BulletShape shape);
630
631public abstract bool IsCompound(BulletShape shape);
632
633public abstract bool IsSoftBody(BulletShape shape);
634
635public abstract bool IsInfinite(BulletShape shape);
636
637public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
638
639public abstract Vector3 GetLocalScaling(BulletShape shape);
640
641public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
642
643public abstract int GetShapeType(BulletShape shape);
644
645public abstract void SetMargin(BulletShape shape, float val);
646
647public abstract float GetMargin(BulletShape shape);
648
649// =====================================================================================
650// Debugging
651public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
652
653public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
654
655public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
656
657public virtual void DumpActivationInfo(BulletWorld sim) { }
658
659public virtual void DumpAllInfo(BulletWorld sim) { }
660
661public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
662
663public virtual void ResetBroadphasePool(BulletWorld sim) { }
664
665public virtual void ResetConstraintSolver(BulletWorld sim) { }
666
667};
668}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..a5fec87 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -58,17 +58,16 @@ public sealed class BSCharacter : BSPhysObject
58 private bool _flying; 58 private bool _flying;
59 private bool _setAlwaysRun; 59 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 60 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 61 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 62 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 63 private bool _kinematic;
66 private float _buoyancy; 64 private float _buoyancy;
67 65
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 66 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity). 67 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 68
69 private BSVMotor _velocityMotor;
70
72 private OMV.Vector3 _PIDTarget; 71 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 72 private bool _usePID;
74 private float _PIDTau; 73 private float _PIDTau;
@@ -83,34 +82,36 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 82 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 83 _position = pos;
85 84
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
92 _flying = isFlying; 85 _flying = isFlying;
93 _orientation = OMV.Quaternion.Identity; 86 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 87 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 88 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 89 _currentFriction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 90 _avatarDensity = BSParam.AvatarDensity;
99 91
100 // The dimensions of the avatar capsule are kept in the scale. 92 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
93 // replace with the default values.
94 _size = size;
95 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
96 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
97
98 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 99 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 100 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 101 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 102 ComputeAvatarVolumeAndMass();
103
104 SetupMovementMotor();
105
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 106 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 107 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 108
108 // do actual create at taint time 109 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 110 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 111 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 113 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 114 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 115
115 SetPhysicalProperties(); 116 SetPhysicalProperties();
116 }); 117 });
@@ -120,54 +121,155 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 121 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 122 public override void Destroy()
122 { 123 {
124 base.Destroy();
125
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 126 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 127 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 128 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 129 PhysicsScene.Shapes.DereferenceBody(PhysBody, true /* inTaintTime */, null /* bodyCallback */);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 130 PhysBody.Clear();
131 PhysicsScene.Shapes.DereferenceShape(PhysShape, true /* inTaintTime */, null /* bodyCallback */);
132 PhysShape.Clear();
128 }); 133 });
129 } 134 }
130 135
131 private void SetPhysicalProperties() 136 private void SetPhysicalProperties()
132 { 137 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 138 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 139
135 ZeroMotion(true); 140 ZeroMotion(true);
136 ForcePosition = _position; 141 ForcePosition = _position;
142
137 // Set the velocity and compute the proper friction 143 // Set the velocity and compute the proper friction
144 _velocityMotor.Reset();
145 _velocityMotor.SetTarget(_velocity);
146 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 147 ForceVelocity = _velocity;
139 148
140 // This will enable or disable the flying buoyancy of the avatar. 149 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 150 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 151 Flying = _flying;
143 152
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 153 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 154 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 155 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 156 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 157 if (BSParam.CcdMotionThreshold > 0f)
149 { 158 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 159 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 160 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 161 }
153 162
154 UpdatePhysicalMassProperties(RawMass); 163 UpdatePhysicalMassProperties(RawMass, false);
155 164
156 // Make so capsule does not fall over 165 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 166 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 167
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 168 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 169
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 170 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 171
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 172 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 173 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 174 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 175
167 // Do this after the object has been added to the world 176 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 177 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 178 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 179 }
180
181 // The avatar's movement is controlled by this motor that speeds up and slows down
182 // the avatar seeking to reach the motor's target speed.
183 // This motor runs as a prestep action for the avatar so it will keep the avatar
184 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
185 private void SetupMovementMotor()
186 {
187 // Infinite decay and timescale values so motor only changes current to target values.
188 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
189 0.2f, // time scale
190 BSMotor.Infinite, // decay time scale
191 BSMotor.InfiniteVector, // friction timescale
192 1f // efficiency
193 );
194 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
195
196 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
197 {
198 // TODO: Decide if the step parameters should be changed depending on the avatar's
199 // state (flying, colliding, ...). There is code in ODE to do this.
200
201 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
202
203 // If falling, we keep the world's downward vector no matter what the other axis specify.
204 if (!Flying && !IsColliding)
205 {
206 stepVelocity.Z = _velocity.Z;
207 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
208 }
209
210 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
211 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
212
213 // Should we check for move force being small and forcing velocity to zero?
214
215 // Add special movement force to allow avatars to walk up stepped surfaces.
216 moveForce += WalkUpStairs();
217
218 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
219 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
220 });
221 }
222
223 // Decide of the character is colliding with a low object and compute a force to pop the
224 // avatar up so it has a chance of walking up and over the low object.
225 private OMV.Vector3 WalkUpStairs()
226 {
227 OMV.Vector3 ret = OMV.Vector3.Zero;
228
229 // This test is done if moving forward, not flying and is colliding with something.
230 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
231 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
232 if (IsColliding && !Flying && TargetSpeed > 0.1f /* && ForwardSpeed < 0.1f */)
233 {
234 // The range near the character's feet where we will consider stairs
235 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
236 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
237
238 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
239 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
240 {
241 // Don't care about collisions with the terrain
242 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
243 {
244 OMV.Vector3 touchPosition = kvp.Value.Position;
245 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
246 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
247 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
248 {
249 // This contact is within the 'near the feet' range.
250 // The normal should be our contact point to the object so it is pointing away
251 // thus the difference between our facing orientation and the normal should be small.
252 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
253 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
254 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
255 if (diff < BSParam.AvatarStepApproachFactor)
256 {
257 // Found the stairs contact point. Push up a little to raise the character.
258 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
259 ret = new OMV.Vector3(0f, 0f, upForce);
260
261 // Also move the avatar up for the new height
262 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
263 ForcePosition = RawPosition + displacement;
264 }
265 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
266 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
267 }
268 }
269 }
270 }
271
272 return ret;
171 } 273 }
172 274
173 public override void RequestPhysicsterseUpdate() 275 public override void RequestPhysicsterseUpdate()
@@ -185,24 +287,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 287 }
186 288
187 set { 289 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 290 _size = value;
190 ComputeAvatarScale(_size); 291 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
292 // replace with the default values.
293 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
294 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
295
296 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 297 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 298 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 299 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
194 300
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 301 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 302 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 303 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 304 {
305 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
306 UpdatePhysicalMassProperties(RawMass, true);
307 // Make sure this change appears as a property update event
308 PhysicsScene.PE.PushUpdate(PhysBody);
309 }
199 }); 310 });
200 311
201 } 312 }
202 } 313 }
203 314
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 315 public override PrimitiveBaseShape Shape
207 { 316 {
208 set { BaseShape = value; } 317 set { BaseShape = value; }
@@ -219,6 +328,10 @@ public sealed class BSCharacter : BSPhysObject
219 public override bool Selected { 328 public override bool Selected {
220 set { _selected = value; } 329 set { _selected = value; }
221 } 330 }
331 public override bool IsSelected
332 {
333 get { return _selected; }
334 }
222 public override void CrossingFailure() { return; } 335 public override void CrossingFailure() { return; }
223 public override void link(PhysicsActor obj) { return; } 336 public override void link(PhysicsActor obj) { return; }
224 public override void delink() { return; } 337 public override void delink() { return; }
@@ -236,7 +349,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 349 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 350 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 351 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 354 });
241 } 355 }
242 public override void ZeroAngularMotion(bool inTaintTime) 356 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +359,13 @@ public sealed class BSCharacter : BSPhysObject
245 359
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 360 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 361 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 362 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 363 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 364 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 365 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
366 // The next also get rid of applied linear force but the linear velocity is untouched.
367 PhysicsScene.PE.ClearForces(PhysBody);
368 }
252 }); 369 });
253 } 370 }
254 371
@@ -263,29 +380,31 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 380 public override OMV.Vector3 Position {
264 get { 381 get {
265 // Don't refetch the position because this function is called a zillion times 382 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 383 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 384 return _position;
268 } 385 }
269 set { 386 set {
270 _position = value; 387 _position = value;
271 PositionSanityCheck();
272 388
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 389 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 390 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 391 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 392 ForcePosition = _position;
277 }); 393 });
278 } 394 }
279 } 395 }
280 public override OMV.Vector3 ForcePosition { 396 public override OMV.Vector3 ForcePosition {
281 get { 397 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 398 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 399 return _position;
284 } 400 }
285 set { 401 set {
286 _position = value; 402 _position = value;
287 PositionSanityCheck(); 403 if (PhysBody.HasPhysicalBody)
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 404 {
405 PositionSanityCheck();
406 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
407 }
289 } 408 }
290 } 409 }
291 410
@@ -297,8 +416,17 @@ public sealed class BSCharacter : BSPhysObject
297 { 416 {
298 bool ret = false; 417 bool ret = false;
299 418
419 // TODO: check for out of bounds
420 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
421 {
422 // The character is out of the known/simulated area.
423 // Upper levels of code will handle the transition to other areas so, for
424 // the time, we just ignore the position.
425 return ret;
426 }
427
300 // If below the ground, move the avatar up 428 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 429 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
302 if (Position.Z < terrainHeight) 430 if (Position.Z < terrainHeight)
303 { 431 {
304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 432 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@@ -307,7 +435,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 435 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 436 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 437 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 438 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 439 if (Position.Z < waterHeight)
312 { 440 {
313 _position.Z = waterHeight; 441 _position.Z = waterHeight;
@@ -315,7 +443,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 443 }
316 } 444 }
317 445
318 // TODO: check for out of bounds
319 return ret; 446 return ret;
320 } 447 }
321 448
@@ -332,7 +459,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 459 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 460 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 461 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 462 if (PhysBody.HasPhysicalBody)
463 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
336 }); 464 });
337 ret = true; 465 ret = true;
338 } 466 }
@@ -345,10 +473,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 473 public override float RawMass {
346 get {return _mass; } 474 get {return _mass; }
347 } 475 }
348 public override void UpdatePhysicalMassProperties(float physMass) 476 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 477 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 478 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 479 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 480 }
353 481
354 public override OMV.Vector3 Force { 482 public override OMV.Vector3 Force {
@@ -359,7 +487,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 487 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 488 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 489 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 490 if (PhysBody.HasPhysicalBody)
491 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 492 });
364 } 493 }
365 } 494 }
@@ -376,6 +505,36 @@ public sealed class BSCharacter : BSPhysObject
376 505
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 506 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 507 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
508
509 // Sets the target in the motor. This starts the changing of the avatar's velocity.
510 public override OMV.Vector3 TargetVelocity
511 {
512 get
513 {
514 return _velocityMotor.TargetValue;
515 }
516 set
517 {
518 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
519 OMV.Vector3 targetVel = value;
520 if (_setAlwaysRun)
521 targetVel *= BSParam.AvatarAlwaysRunFactor;
522
523 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
524 {
525 _velocityMotor.Reset();
526 _velocityMotor.SetTarget(targetVel);
527 _velocityMotor.SetCurrent(_velocity);
528 _velocityMotor.Enabled = true;
529 });
530 }
531 }
532 public override OMV.Vector3 RawVelocity
533 {
534 get { return _velocity; }
535 set { _velocity = value; }
536 }
537 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 538 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 539 get { return _velocity; }
381 set { 540 set {
@@ -383,6 +542,12 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 542 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 543 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 544 {
545 _velocityMotor.Reset();
546 _velocityMotor.SetCurrent(_velocity);
547 _velocityMotor.SetTarget(_velocity);
548 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
549 _velocityMotor.Enabled = false;
550
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 551 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 552 ForceVelocity = _velocity;
388 }); 553 });
@@ -391,30 +556,32 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 556 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 557 get { return _velocity; }
393 set { 558 set {
559 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
560
561 _velocity = value;
394 // Depending on whether the avatar is moving or not, change the friction 562 // Depending on whether the avatar is moving or not, change the friction
395 // to keep the avatar from slipping around 563 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0) 564 if (_velocity.Length() == 0)
397 { 565 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 566 if (_currentFriction != BSParam.AvatarStandingFriction)
399 { 567 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 568 _currentFriction = BSParam.AvatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 569 if (PhysBody.HasPhysicalBody)
570 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
402 } 571 }
403 } 572 }
404 else 573 else
405 { 574 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction) 575 if (_currentFriction != BSParam.AvatarFriction)
407 { 576 {
408 _currentFriction = PhysicsScene.Params.avatarFriction; 577 _currentFriction = BSParam.AvatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 578 if (PhysBody.HasPhysicalBody)
579 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
410 } 580 }
411 } 581 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415 582
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 583 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 584 PhysicsScene.PE.Activate(PhysBody, true);
418 } 585 }
419 } 586 }
420 public override OMV.Vector3 Torque { 587 public override OMV.Vector3 Torque {
@@ -439,13 +606,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 606 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 607 get { return _orientation; }
441 set { 608 set {
442 _orientation = value; 609 // Orientation is set zillions of times when an avatar is walking. It's like
443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 610 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 611 if (_orientation != value)
445 { 612 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 613 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 614 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 615 {
616 ForceOrientation = _orientation;
617 });
618 }
449 } 619 }
450 } 620 }
451 // Go directly to Bullet to get/set the value. 621 // Go directly to Bullet to get/set the value.
@@ -453,13 +623,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 623 {
454 get 624 get
455 { 625 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 626 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 627 return _orientation;
458 } 628 }
459 set 629 set
460 { 630 {
461 _orientation = value; 631 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 632 if (PhysBody.HasPhysicalBody)
633 {
634 // _position = PhysicsScene.PE.GetPosition(BSBody);
635 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
636 }
463 } 637 }
464 } 638 }
465 public override int PhysicsActorType { 639 public override int PhysicsActorType {
@@ -482,6 +656,7 @@ public sealed class BSCharacter : BSPhysObject
482 get { return _flying; } 656 get { return _flying; }
483 set { 657 set {
484 _flying = value; 658 _flying = value;
659
485 // simulate flying by changing the effect of gravity 660 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 661 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 662 }
@@ -500,27 +675,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 675 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 676 set { _throttleUpdates = value; }
502 } 677 }
503 public override bool IsColliding {
504 get { return (CollidingStep == PhysicsScene.SimulationStep); }
505 set { _isColliding = value; }
506 }
507 public override bool CollidingGround {
508 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
509 set { CollidingGround = value; }
510 }
511 public override bool CollidingObj {
512 get { return _collidingObj; }
513 set { _collidingObj = value; }
514 }
515 public override bool FloatOnWater { 678 public override bool FloatOnWater {
516 set { 679 set {
517 _floatOnWater = value; 680 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 681 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 682 {
520 if (_floatOnWater) 683 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 684 {
522 else 685 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 686 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
687 else
688 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
689 }
524 }); 690 });
525 } 691 }
526 } 692 }
@@ -549,11 +715,15 @@ public sealed class BSCharacter : BSPhysObject
549 } 715 }
550 public override float ForceBuoyancy { 716 public override float ForceBuoyancy {
551 get { return _buoyancy; } 717 get { return _buoyancy; }
552 set { _buoyancy = value; 718 set {
719 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
720
721 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 722 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 723 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 724 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 725 if (PhysBody.HasPhysicalBody)
726 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
557 } 727 }
558 } 728 }
559 729
@@ -589,24 +759,40 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 759 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 760 public override float APIDDamping { set { return; } }
591 761
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 762 public override void AddForce(OMV.Vector3 force, bool pushforce)
763 {
764 // Since this force is being applied in only one step, make this a force per second.
765 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
766 AddForce(addForce, pushforce, false);
767 }
768 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 769 if (force.IsFinite())
594 { 770 {
595 _force.X += force.X; 771 float magnitude = force.Length();
596 _force.Y += force.Y; 772 if (magnitude > BSParam.MaxAddForceMagnitude)
597 _force.Z += force.Z;
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 773 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 774 // Force has a limit
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 775 force = force / magnitude * BSParam.MaxAddForceMagnitude;
776 }
777
778 OMV.Vector3 addForce = force;
779 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
780
781 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
782 {
783 // Bullet adds this central force to the total force for this tick
784 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
785 if (PhysBody.HasPhysicalBody)
786 {
787 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
788 }
603 }); 789 });
604 } 790 }
605 else 791 else
606 { 792 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 793 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
794 return;
608 } 795 }
609 //m_lastUpdateSent = false;
610 } 796 }
611 797
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 798 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +800,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 800 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 801 }
616 802
617 private void ComputeAvatarScale(OMV.Vector3 size) 803 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 804 {
619 // The 'size' given by the simulator is the mid-point of the avatar 805 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 806
621 807 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 808 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 809 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 810 // shape to be the size desired.
625 811 // So, when creating the scale for the avatar height, we take the passed height
626 // From the total height, remove the capsule half spheres that are at each end 812 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 813 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 814 // dimension is the radius of the capsule. Even though some of the code allows
815 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
816
817 // Scale is multiplier of radius with one of "0.5"
818 newScale.X = size.X / 2f;
819 newScale.Y = size.Y / 2f;
629 820
630 // The total scale height is the central cylindar plus the caps on the two ends. 821 // The total scale height is the central cylindar plus the caps on the two ends.
631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); 822 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
823 // If smaller than the endcaps, just fake like we're almost that small
824 if (newScale.Z < 0)
825 newScale.Z = 0.1f;
632 826
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 827 return newScale;
634 Scale = newScale / 2f;
635 } 828 }
636 829
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 830 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,14 +832,14 @@ public sealed class BSCharacter : BSPhysObject
639 { 832 {
640 _avatarVolume = (float)( 833 _avatarVolume = (float)(
641 Math.PI 834 Math.PI
642 * Scale.X 835 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 836 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 837 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 838 + 1.33333333f
646 * Math.PI 839 * Math.PI
647 * Scale.X 840 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 841 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 842 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 843 );
651 _mass = _avatarDensity * _avatarVolume; 844 _mass = _avatarDensity * _avatarVolume;
652 } 845 }
@@ -660,6 +853,7 @@ public sealed class BSCharacter : BSPhysObject
660 _velocity = entprop.Velocity; 853 _velocity = entprop.Velocity;
661 _acceleration = entprop.Acceleration; 854 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 855 _rotationalVelocity = entprop.RotationalVelocity;
856
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 857 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 858 PositionSanityCheck(true);
665 859
@@ -667,17 +861,8 @@ public sealed class BSCharacter : BSPhysObject
667 LastEntityProperties = CurrentEntityProperties; 861 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 862 CurrentEntityProperties = entprop;
669 863
670 if (entprop.Velocity != LastEntityProperties.Velocity)
671 {
672 // Changes in the velocity are suppressed in avatars.
673 // That's just the way they are defined.
674 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
675 _velocity = avVel;
676 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
677 }
678
679 // Tell the linkset about value changes 864 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 865 Linkset.UpdateProperties(this, true);
681 866
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 867 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 868 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 65fac00..b813974 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -36,7 +36,8 @@ public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38 38
39 protected BulletSim m_world; 39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
40 protected BulletBody m_body1; 41 protected BulletBody m_body1;
41 protected BulletBody m_body2; 42 protected BulletBody m_body2;
42 protected BulletConstraint m_constraint; 43 protected BulletConstraint m_constraint;
@@ -48,8 +49,10 @@ public abstract class BSConstraint : IDisposable
48 public abstract ConstraintType Type { get; } 49 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } } 50 public bool IsEnabled { get { return m_enabled; } }
50 51
51 public BSConstraint() 52 public BSConstraint(BulletWorld world)
52 { 53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
53 } 56 }
54 57
55 public virtual void Dispose() 58 public virtual void Dispose()
@@ -57,15 +60,15 @@ public abstract class BSConstraint : IDisposable
57 if (m_enabled) 60 if (m_enabled)
58 { 61 {
59 m_enabled = false; 62 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero) 63 if (m_constraint.HasPhysicalConstraint)
61 { 64 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
64 BSScene.DetailLogZero, 67 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString("X"), 68 m_body1.ID, m_body1.AddrString,
66 m_body2.ID, m_body2.ptr.ToString("X"), 69 m_body2.ID, m_body2.AddrString,
67 success); 70 success);
68 m_constraint.ptr = System.IntPtr.Zero; 71 m_constraint.Clear();
69 } 72 }
70 } 73 }
71 } 74 }
@@ -74,7 +77,7 @@ public abstract class BSConstraint : IDisposable
74 { 77 {
75 bool ret = false; 78 bool ret = false;
76 if (m_enabled) 79 if (m_enabled)
77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); 80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
78 return ret; 81 return ret;
79 } 82 }
80 83
@@ -82,7 +85,7 @@ public abstract class BSConstraint : IDisposable
82 { 85 {
83 bool ret = false; 86 bool ret = false;
84 if (m_enabled) 87 if (m_enabled)
85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); 88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
86 return ret; 89 return ret;
87 } 90 }
88 91
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
91 bool ret = false; 94 bool ret = false;
92 if (m_enabled) 95 if (m_enabled)
93 { 96 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); 97 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
95 ret = true; 98 ret = true;
96 } 99 }
97 return ret; 100 return ret;
@@ -103,7 +106,7 @@ public abstract class BSConstraint : IDisposable
103 if (m_enabled) 106 if (m_enabled)
104 { 107 {
105 // Recompute the internal transforms 108 // Recompute the internal transforms
106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr); 109 PhysicsScene.PE.CalculateTransforms(m_constraint);
107 ret = true; 110 ret = true;
108 } 111 }
109 return ret; 112 return ret;
@@ -122,7 +125,7 @@ public abstract class BSConstraint : IDisposable
122 // Setting an object's mass to zero (making it static like when it's selected) 125 // Setting an object's mass to zero (making it static like when it's selected)
123 // automatically disables the constraints. 126 // automatically disables the constraints.
124 // If the link is enabled, be sure to set the constraint itself to enabled. 127 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); 128 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
126 } 129 }
127 else 130 else
128 { 131 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 23ef052..ecb1b32 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -39,51 +39,49 @@ public sealed class BSConstraint6Dof : BSConstraint
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
46 : base(world)
46 { 47 {
47 m_world = world;
48 m_body1 = obj1; 48 m_body1 = obj1;
49 m_body2 = obj2; 49 m_body2 = obj2;
50 m_constraint = new BulletConstraint( 50 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
52 frame1, frame1rot, 51 frame1, frame1rot,
53 frame2, frame2rot, 52 frame2, frame2rot,
54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
55 m_enabled = true; 54 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID, 56 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
59 } 58 }
60 59
61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 61 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
63 : base(world)
64 { 64 {
65 m_world = world;
66 m_body1 = obj1; 65 m_body1 = obj1;
67 m_body2 = obj2; 66 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 67 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 68 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 69 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 70 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 71 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 72 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 73 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
75 m_enabled = false; 74 m_enabled = false;
76 } 75 }
77 else 76 else
78 { 77 {
79 m_constraint = new BulletConstraint( 78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint, 79 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 81 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"), 82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
86 if (m_constraint.ptr == IntPtr.Zero) 84 if (!m_constraint.HasPhysicalConstraint)
87 { 85 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 87 LogHeader, obj1.ID, obj2.ID);
@@ -101,7 +99,7 @@ public sealed class BSConstraint6Dof : BSConstraint
101 bool ret = false; 99 bool ret = false;
102 if (m_enabled) 100 if (m_enabled)
103 { 101 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 102 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
105 ret = true; 103 ret = true;
106 } 104 }
107 return ret; 105 return ret;
@@ -112,9 +110,9 @@ public sealed class BSConstraint6Dof : BSConstraint
112 bool ret = false; 110 bool ret = false;
113 if (m_enabled) 111 if (m_enabled)
114 { 112 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 113 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 114 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 115 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true; 116 ret = true;
119 } 117 }
120 return ret; 118 return ret;
@@ -125,7 +123,7 @@ public sealed class BSConstraint6Dof : BSConstraint
125 bool ret = false; 123 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 124 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled) 125 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); 126 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
129 return ret; 127 return ret;
130 } 128 }
131 129
@@ -135,7 +133,7 @@ public sealed class BSConstraint6Dof : BSConstraint
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 133 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled) 134 if (m_enabled)
137 { 135 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 136 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", 137 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); 138 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 } 139 }
@@ -146,7 +144,7 @@ public sealed class BSConstraint6Dof : BSConstraint
146 { 144 {
147 bool ret = false; 145 bool ret = false;
148 if (m_enabled) 146 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); 147 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
150 return ret; 148 return ret;
151 } 149 }
152} 150}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index a9fd826..2aeff25 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -41,9 +41,9 @@ public sealed class BSConstraintCollection : IDisposable
41 delegate bool ConstraintAction(BSConstraint constrain); 41 delegate bool ConstraintAction(BSConstraint constrain);
42 42
43 private List<BSConstraint> m_constraints; 43 private List<BSConstraint> m_constraints;
44 private BulletSim m_world; 44 private BulletWorld m_world;
45 45
46 public BSConstraintCollection(BulletSim world) 46 public BSConstraintCollection(BulletWorld world)
47 { 47 {
48 m_world = world; 48 m_world = world;
49 m_constraints = new List<BSConstraint>(); 49 m_constraints = new List<BSConstraint>();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index ed3ffa7..7714a03 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -36,19 +36,17 @@ public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 38
39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
43 { 44 {
44 m_world = world;
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = new BulletConstraint( 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, 48 pivotInA, pivotInB, axisInA, axisInB,
49 pivotInA, pivotInB, 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true; 50 m_enabled = true;
53 } 51 }
54 52
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..e434412 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,16 +80,18 @@ 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
94 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
106 private float m_angularDeflectionEfficiency = 0; 95 private float m_angularDeflectionEfficiency = 0;
107 private float m_angularDeflectionTimescale = 0; 96 private float m_angularDeflectionTimescale = 0;
108 private float m_linearDeflectionEfficiency = 0; 97 private float m_linearDeflectionEfficiency = 0;
@@ -114,32 +103,61 @@ namespace OpenSim.Region.Physics.BulletSPlugin
114 private float m_bankingTimescale = 0; 103 private float m_bankingTimescale = 0;
115 104
116 //Hover and Buoyancy properties 105 //Hover and Buoyancy properties
106 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
117 private float m_VhoverHeight = 0f; 107 private float m_VhoverHeight = 0f;
118 private float m_VhoverEfficiency = 0f; 108 private float m_VhoverEfficiency = 0f;
119 private float m_VhoverTimescale = 0f; 109 private float m_VhoverTimescale = 0f;
120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
121 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 111 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
122 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) 112 private float m_VehicleBuoyancy = 0f;
123 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 113 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
124 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
125 114
126 //Attractor properties 115 //Attractor properties
127 private float m_verticalAttractionEfficiency = 1.0f; // damped 116 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 117 private float m_verticalAttractionEfficiency = 1.0f; // damped
118 private float m_verticalAttractionCutoff = 500f; // per the documentation
119 // Timescale > cutoff means no vert attractor.
120 private float m_verticalAttractionTimescale = 510f;
121
122 // Just some recomputed constants:
123 static readonly float PIOverFour = ((float)Math.PI) / 4f;
124 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
125
126 // For debugging, flags to turn on and off individual corrections.
127 private bool enableAngularVerticalAttraction;
128 private bool enableAngularDeflection;
129 private bool enableAngularBanking;
129 130
130 public BSDynamics(BSScene myScene, BSPrim myPrim) 131 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 { 132 {
132 PhysicsScene = myScene; 133 PhysicsScene = myScene;
133 Prim = myPrim; 134 Prim = myPrim;
134 Type = Vehicle.TYPE_NONE; 135 Type = Vehicle.TYPE_NONE;
136 SetupVehicleDebugging();
137 }
138
139 // Stopgap debugging enablement. Allows source level debugging but still checking
140 // in changes by making enablement of debugging flags from INI file.
141 public void SetupVehicleDebugging()
142 {
143 enableAngularVerticalAttraction = true;
144 enableAngularDeflection = false;
145 enableAngularBanking = false;
146 if (BSParam.VehicleDebuggingEnabled != ConfigurationParameters.numericFalse)
147 {
148 enableAngularVerticalAttraction = false;
149 enableAngularDeflection = false;
150 enableAngularBanking = false;
151 }
135 } 152 }
136 153
137 // Return 'true' if this vehicle is doing vehicle things 154 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive 155 public bool IsActive
139 { 156 {
140 get { return Type != Vehicle.TYPE_NONE; } 157 get { return (Type != Vehicle.TYPE_NONE && !Prim.IsStatic); }
141 } 158 }
142 159
160 #region Vehicle parameter setting
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 161 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
144 { 162 {
145 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 163 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
@@ -152,13 +170,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 170 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 171 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 172 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 173 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
174 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 175 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 176 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 177 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
178 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 179 break;
160 case Vehicle.BANKING_EFFICIENCY: 180 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 181 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 182 break;
163 case Vehicle.BANKING_MIX: 183 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 184 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +187,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 187 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 188 break;
169 case Vehicle.BUOYANCY: 189 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 190 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
191 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
171 break; 192 break;
172 case Vehicle.HOVER_EFFICIENCY: 193 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 194 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 195 break;
175 case Vehicle.HOVER_HEIGHT: 196 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 197 m_VhoverHeight = pValue;
@@ -185,33 +206,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 206 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 207 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 208 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 209 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
210 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 211 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 212 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 213 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
214 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 215 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 216 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 217 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
218 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 219 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 220 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 221 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
222 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 223 break;
199 224
200 // These are vector properties but the engine lets you use a single float value to 225 // 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 226 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 227 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 228 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
229 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 230 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 231 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 232 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 233 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 234 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 235 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 236 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
237 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 238 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 239 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 240 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 241 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
242 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 243 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 244 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 245 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +255,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 255 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 256 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 257 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
258 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 259 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 260 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 261 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 262 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 263 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 264 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 266 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 267 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 268 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 269 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
270 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 271 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 272 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 273 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 274 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
275 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 276 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 277 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 278 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +334,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 334 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 335 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 336 m_VehicleBuoyancy = 0;
306 337
307 m_linearDeflectionEfficiency = 1; 338 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 339 m_linearDeflectionTimescale = 1;
309 340
@@ -319,6 +350,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 350
320 m_referenceFrame = Quaternion.Identity; 351 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 352 m_flags = (VehicleFlag)0;
353
322 break; 354 break;
323 355
324 case Vehicle.TYPE_SLED: 356 case Vehicle.TYPE_SLED:
@@ -351,10 +383,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 383 m_bankingMix = 1;
352 384
353 m_referenceFrame = Quaternion.Identity; 385 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 386 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 387 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 388 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 389 | VehicleFlag.HOVER_UP_ONLY);
390 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
391 | VehicleFlag.LIMIT_ROLL_ONLY
392 | VehicleFlag.LIMIT_MOTOR_UP);
393
358 break; 394 break;
359 case Vehicle.TYPE_CAR: 395 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 396 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +534,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 534 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 535 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 536 m_bankingTimescale = 5;
537
501 m_referenceFrame = Quaternion.Identity; 538 m_referenceFrame = Quaternion.Identity;
502 539
503 m_referenceFrame = Quaternion.Identity; 540 m_referenceFrame = Quaternion.Identity;
@@ -510,7 +547,30 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 547 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 548 break;
512 } 549 }
550
551 // Update any physical parameters based on this type.
552 Refresh();
553
554 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
555 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
556 1f);
557 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
558
559 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
560 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
561 1f);
562 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
563
564 /* Not implemented
565 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
566 BSMotor.Infinite, BSMotor.InfiniteVector,
567 m_verticalAttractionEfficiency);
568 // Z goes away and we keep X and Y
569 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
570 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
571 */
513 } 572 }
573 #endregion // Vehicle parameter setting
514 574
515 // Some of the properties of this prim may have changed. 575 // Some of the properties of this prim may have changed.
516 // Do any updating needed for a vehicle 576 // Do any updating needed for a vehicle
@@ -518,13 +578,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 578 {
519 if (IsActive) 579 if (IsActive)
520 { 580 {
521 // Friction effects are handled by this vehicle code 581 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 582 m_vehicleMass = Prim.Linkset.LinksetMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); 583
524 584 // Friction affects are handled by this vehicle code
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 585 float friction = 0f;
526 586 PhysicsScene.PE.SetFriction(Prim.PhysBody, friction);
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 587
588 // Moderate angular movement introduced by Bullet.
589 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
590 // Maybe compute linear and angular factor and damping from params.
591 float angularDamping = BSParam.VehicleAngularDamping;
592 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping);
593
594 // Vehicles report collision events so we know when it's on the ground
595 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
596
597 Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
598 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia);
599 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
600
601 // Set the gravity for the vehicle depending on the buoyancy
602 // TODO: what should be done if prim and vehicle buoyancy differ?
603 m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy);
604 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
605 PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero);
606
607 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4},grav={5}",
608 Prim.LocalID, m_vehicleMass, friction, Prim.Inertia, angularDamping, m_VehicleGravity);
609 }
610 else
611 {
612 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 613 }
529 } 614 }
530 615
@@ -546,116 +631,383 @@ namespace OpenSim.Region.Physics.BulletSPlugin
546 Refresh(); 631 Refresh();
547 } 632 }
548 633
634 #region Known vehicle value functions
635 // Vehicle physical parameters that we buffer from constant getting and setting.
636 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
637 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
638 // This does two things: 1) saves continuious calls into unmanaged code, and
639 // 2) signals when a physics property update must happen back to the simulator
640 // to update values modified for the vehicle.
641 private int m_knownChanged;
642 private int m_knownHas;
643 private float m_knownTerrainHeight;
644 private float m_knownWaterLevel;
645 private Vector3 m_knownPosition;
646 private Vector3 m_knownVelocity;
647 private Vector3 m_knownForce;
648 private Vector3 m_knownForceImpulse;
649 private Quaternion m_knownOrientation;
650 private Vector3 m_knownRotationalVelocity;
651 private Vector3 m_knownRotationalForce;
652 private Vector3 m_knownRotationalImpulse;
653 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
654
655 private const int m_knownChangedPosition = 1 << 0;
656 private const int m_knownChangedVelocity = 1 << 1;
657 private const int m_knownChangedForce = 1 << 2;
658 private const int m_knownChangedForceImpulse = 1 << 3;
659 private const int m_knownChangedOrientation = 1 << 4;
660 private const int m_knownChangedRotationalVelocity = 1 << 5;
661 private const int m_knownChangedRotationalForce = 1 << 6;
662 private const int m_knownChangedRotationalImpulse = 1 << 7;
663 private const int m_knownChangedTerrainHeight = 1 << 8;
664 private const int m_knownChangedWaterLevel = 1 << 9;
665 private const int m_knownChangedForwardVelocity = 1 <<10;
666
667 private void ForgetKnownVehicleProperties()
668 {
669 m_knownHas = 0;
670 m_knownChanged = 0;
671 }
672 // Push all the changed values back into the physics engine
673 private void PushKnownChanged()
674 {
675 if (m_knownChanged != 0)
676 {
677 if ((m_knownChanged & m_knownChangedPosition) != 0)
678 Prim.ForcePosition = m_knownPosition;
679
680 if ((m_knownChanged & m_knownChangedOrientation) != 0)
681 Prim.ForceOrientation = m_knownOrientation;
682
683 if ((m_knownChanged & m_knownChangedVelocity) != 0)
684 {
685 Prim.ForceVelocity = m_knownVelocity;
686 // Fake out Bullet by making it think the velocity is the same as last time.
687 // Bullet does a bunch of smoothing for changing parameters.
688 // Since the vehicle is demanding this setting, we override Bullet's smoothing
689 // by telling Bullet the value was the same last time.
690 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
691 }
692
693 if ((m_knownChanged & m_knownChangedForce) != 0)
694 Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
695
696 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
697 Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
698
699 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
700 {
701 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
702 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
703 }
704
705 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
706 Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
707
708 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
709 {
710 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
711 }
712
713 // If we set one of the values (ie, the physics engine didn't do it) we must force
714 // an UpdateProperties event to send the changes up to the simulator.
715 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
716 }
717 m_knownChanged = 0;
718 }
719
720 // Since the computation of terrain height can be a little involved, this routine
721 // is used to fetch the height only once for each vehicle simulation step.
722 private float GetTerrainHeight(Vector3 pos)
723 {
724 if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
725 {
726 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
727 m_knownHas |= m_knownChangedTerrainHeight;
728 }
729 return m_knownTerrainHeight;
730 }
731
732 // Since the computation of water level can be a little involved, this routine
733 // is used ot fetch the level only once for each vehicle simulation step.
734 private float GetWaterLevel(Vector3 pos)
735 {
736 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
737 {
738 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
739 m_knownHas |= m_knownChangedWaterLevel;
740 }
741 return (float)m_knownWaterLevel;
742 }
743
744 private Vector3 VehiclePosition
745 {
746 get
747 {
748 if ((m_knownHas & m_knownChangedPosition) == 0)
749 {
750 m_knownPosition = Prim.ForcePosition;
751 m_knownHas |= m_knownChangedPosition;
752 }
753 return m_knownPosition;
754 }
755 set
756 {
757 m_knownPosition = value;
758 m_knownChanged |= m_knownChangedPosition;
759 m_knownHas |= m_knownChangedPosition;
760 }
761 }
762
763 private Quaternion VehicleOrientation
764 {
765 get
766 {
767 if ((m_knownHas & m_knownChangedOrientation) == 0)
768 {
769 m_knownOrientation = Prim.ForceOrientation;
770 m_knownHas |= m_knownChangedOrientation;
771 }
772 return m_knownOrientation;
773 }
774 set
775 {
776 m_knownOrientation = value;
777 m_knownChanged |= m_knownChangedOrientation;
778 m_knownHas |= m_knownChangedOrientation;
779 }
780 }
781
782 private Vector3 VehicleVelocity
783 {
784 get
785 {
786 if ((m_knownHas & m_knownChangedVelocity) == 0)
787 {
788 m_knownVelocity = Prim.ForceVelocity;
789 m_knownHas |= m_knownChangedVelocity;
790 }
791 return (Vector3)m_knownVelocity;
792 }
793 set
794 {
795 m_knownVelocity = value;
796 m_knownChanged |= m_knownChangedVelocity;
797 m_knownHas |= m_knownChangedVelocity;
798 }
799 }
800
801 private void VehicleAddForce(Vector3 pForce)
802 {
803 if ((m_knownHas & m_knownChangedForce) == 0)
804 {
805 m_knownForce = Vector3.Zero;
806 m_knownHas |= m_knownChangedForce;
807 }
808 m_knownForce += pForce;
809 m_knownChanged |= m_knownChangedForce;
810 }
811
812 private void VehicleAddForceImpulse(Vector3 pImpulse)
813 {
814 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
815 {
816 m_knownForceImpulse = Vector3.Zero;
817 m_knownHas |= m_knownChangedForceImpulse;
818 }
819 m_knownForceImpulse += pImpulse;
820 m_knownChanged |= m_knownChangedForceImpulse;
821 }
822
823 private Vector3 VehicleRotationalVelocity
824 {
825 get
826 {
827 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
828 {
829 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
830 m_knownHas |= m_knownChangedRotationalVelocity;
831 }
832 return (Vector3)m_knownRotationalVelocity;
833 }
834 set
835 {
836 m_knownRotationalVelocity = value;
837 m_knownChanged |= m_knownChangedRotationalVelocity;
838 m_knownHas |= m_knownChangedRotationalVelocity;
839 }
840 }
841 private void VehicleAddAngularForce(Vector3 aForce)
842 {
843 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
844 {
845 m_knownRotationalForce = Vector3.Zero;
846 }
847 m_knownRotationalForce += aForce;
848 m_knownChanged |= m_knownChangedRotationalForce;
849 m_knownHas |= m_knownChangedRotationalForce;
850 }
851 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
852 {
853 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
854 {
855 m_knownRotationalImpulse = Vector3.Zero;
856 m_knownHas |= m_knownChangedRotationalImpulse;
857 }
858 m_knownRotationalImpulse += pImpulse;
859 m_knownChanged |= m_knownChangedRotationalImpulse;
860 }
861
862 // Vehicle relative forward velocity
863 private Vector3 VehicleForwardVelocity
864 {
865 get
866 {
867 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
868 {
869 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
870 m_knownHas |= m_knownChangedForwardVelocity;
871 }
872 return m_knownForwardVelocity;
873 }
874 }
875 private float VehicleForwardSpeed
876 {
877 get
878 {
879 return VehicleForwardVelocity.X;
880 }
881 }
882
883 #endregion // Known vehicle value functions
884
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 885 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 886 internal void Step(float pTimestep)
551 { 887 {
552 if (!IsActive) return; 888 if (!IsActive) return;
553 889
554 // DEBUG 890 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
555 // Because Bullet does apply forces to the vehicle, our last computed 891 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
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 892
563 m_vehicleMass = Prim.Linkset.LinksetMass; 893 ForgetKnownVehicleProperties();
564 894
565 MoveLinear(pTimestep); 895 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 896 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 897
571 LimitRotation(pTimestep); 898 LimitRotation(pTimestep);
572 899
573 // remember the position so next step we can limit absolute movement effects 900 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 901 m_lastPositionVector = VehiclePosition;
575 902
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 903 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 904 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 905 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
585 }// end Step
586 906
587 // Apply the effect of the linear motor. 907 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
588 // Also does hover and float. 908 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
909
910 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
911 Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
912 }
913
914 // Apply the effect of the linear motor and other linear motions (like hover and float).
589 private void MoveLinear(float pTimestep) 915 private void MoveLinear(float pTimestep)
590 { 916 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 917 ComputeLinearVelocity(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction 918
593 if (m_linearMotorDirection.LengthSquared() > 0.001f) 919 ComputeLinearTerrainHeightCorrection(pTimestep);
920
921 ComputeLinearHover(pTimestep);
922
923 ComputeLinearBlockingEndPoint(pTimestep);
924
925 ComputeLinearMotorUp(pTimestep);
926
927 ApplyGravity(pTimestep);
928
929 // If not changing some axis, reduce out velocity
930 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
931 {
932 Vector3 vel = VehicleVelocity;
933 if ((m_flags & (VehicleFlag.NO_X)) != 0)
934 vel.X = 0;
935 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
936 vel.Y = 0;
937 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
938 vel.Z = 0;
939 VehicleVelocity = vel;
940 }
941
942 // ==================================================================
943 // Clamp high or low velocities
944 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
945 if (newVelocityLengthSq > 1000f)
594 { 946 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG 947 VehicleVelocity /= VehicleVelocity.Length();
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG 948 VehicleVelocity *= 1000f;
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison 949 }
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG 950 else if (newVelocityLengthSq < 0.001f)
951 VehicleVelocity = Vector3.Zero;
599 952
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 953 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity );
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
602 m_lastLinearVelocityVector += addAmount;
603 954
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 955 } // end MoveLinear()
605 m_linearMotorDirection *= (1f - decayFactor);
606 956
607 // Rotate new object velocity from vehicle relative to world coordinates 957 public void ComputeLinearVelocity(float pTimestep)
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; 958 {
959 Vector3 linearMotorStep = m_linearMotor.Step(pTimestep);
609 960
610 // Apply friction for next time 961 // The movement computed in the linear motor is relative to the vehicle
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; 962 // coordinates. Rotate the movement to world coordinates.
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); 963 Vector3 linearMotorVelocity = linearMotorStep * VehicleOrientation;
613 964
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 965 // If we're a ground vehicle, don't loose any Z action (like gravity acceleration).
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 966 float mixFactor = 1f; // 1 means use all linear motor Z value, 0 means use all existing Z
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 967 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
968 {
969 if (!Prim.IsColliding)
970 {
971 // If a ground vehicle and not on the ground, I want gravity effect
972 mixFactor = 0.2f;
973 }
617 } 974 }
618 else 975 else
619 { 976 {
620 // if what remains of direction is very small, zero it. 977 // I'm not a ground vehicle but don't totally loose the effect of the environment
621 m_linearMotorDirection = Vector3.Zero; 978 mixFactor = 0.8f;
622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
626 } 979 }
980 linearMotorVelocity.Z = mixFactor * linearMotorVelocity.Z + (1f - mixFactor) * VehicleVelocity.Z;
627 981
628 // m_newVelocity is velocity computed from linear motor in world coordinates 982 // What we want to contribute to the vehicle's existing velocity
983 Vector3 linearMotorForce = linearMotorVelocity - VehicleVelocity;
629 984
630 // Gravity and Buoyancy 985 // Act against the inertia of the vehicle
631 // There is some gravity, make a gravity force vector that is applied after object velocity. 986 linearMotorForce *= m_vehicleMass;
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
634 987
635 /* 988 VehicleAddForceImpulse(linearMotorForce * pTimestep);
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
637 // Preserve the current Z velocity
638 Vector3 vel_now = m_prim.Velocity;
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
640 */
641 989
642 Vector3 pos = Prim.ForcePosition; 990 VDetailLog("{0}, MoveLinear,velocity,vehVel={1},step={2},stepVel={3},mix={4},force={5}",
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); 991 Prim.LocalID, VehicleVelocity, linearMotorStep, linearMotorVelocity, mixFactor, linearMotorForce);
992 }
644 993
994 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
995 {
645 // If below the terrain, move us above the ground a little. 996 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 997 // 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. 998 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 { 999 {
653 pos.Z = terrainHeight + 2; 1000 // Force position because applying force won't get the vehicle through the terrain
654 Prim.ForcePosition = pos; 1001 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 1002 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1003 VehiclePosition = newPosition;
1004 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1005 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 1006 }
1007 }
657 1008
658 // Check if hovering 1009 public void ComputeLinearHover(float pTimestep)
1010 {
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1011 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 1012 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1013 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +1015,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 1015 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1016 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 1017 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 1018 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 1019 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 1020 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 1021 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 1022 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 1023 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 1024 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 1025 {
@@ -677,45 +1029,63 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1029 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 1030 {
679 // If body is already heigher, use its height as target height 1031 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 1032 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 1033 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 1034 }
1035
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1036 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 1037 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 1038 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 1039 {
1040 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 1041 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 1042 VehiclePosition = pos;
1043
1044 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos);
689 } 1045 }
690 } 1046 }
691 else 1047 else
692 { 1048 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 1049 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 1050 Vector3 hpos = VehiclePosition;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 1051 float verticalError = m_VhoverTargetHeight - hpos.Z;
696 // Replace Vertical speed with correction figure if significant 1052 float verticalCorrection = verticalError / m_VhoverTimescale;
697 if (Math.Abs(verticalError) > 0.01f) 1053 verticalCorrection *= m_VhoverEfficiency;
698 { 1054
699 m_newVelocity.Z += verticalCorrectionVelocity; 1055 hpos.Z += verticalCorrection;
700 //KF: m_VhoverEfficiency is not yet implemented 1056 VehiclePosition = hpos;
701 } 1057
702 else if (verticalError < -0.01) 1058 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
703 { 1059 Vector3 vel = VehicleVelocity;
704 m_newVelocity.Z -= verticalCorrectionVelocity; 1060 vel.Z = 0f;
705 } 1061 VehicleVelocity = vel;
706 else 1062
707 { 1063 /*
708 m_newVelocity.Z = 0f; 1064 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
709 } 1065 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1066 verticalCorrection *= m_vehicleMass;
1067
1068 // TODO: implement m_VhoverEfficiency correctly
1069 VehicleAddForceImpulse(verticalCorrection);
1070 */
1071
1072 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1073 Prim.LocalID, VehiclePosition, m_VhoverEfficiency,
1074 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1075 verticalError, verticalCorrection);
710 } 1076 }
711 1077
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
713 } 1078 }
1079 }
1080
1081 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1082 {
1083 bool changed = false;
714 1084
1085 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 1086 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 1087 if (m_BlockingEndPoint != Vector3.Zero)
717 { 1088 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 1089 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 1090 {
721 pos.X -= posChange.X + 1; 1091 pos.X -= posChange.X + 1;
@@ -743,233 +1113,152 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 1113 }
744 if (changed) 1114 if (changed)
745 { 1115 {
746 Prim.ForcePosition = pos; 1116 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1117 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1118 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 1119 }
750 } 1120 }
1121 return changed;
1122 }
751 1123
752 #region downForce 1124 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 1125 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1126 // used with conjunction with banking: the strength of the banking will decay when the
1127 // vehicle no longer experiences collisions. The decay timescale is the same as
1128 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1129 // when they are in mid jump.
1130 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1131 // This is just using the ground and a general collision check. Should really be using
1132 // a downward raycast to find what is below.
1133 public void ComputeLinearMotorUp(float pTimestep)
1134 {
1135 Vector3 ret = Vector3.Zero;
754 1136
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1137 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1138 {
757 // If the vehicle is motoring into the sky, get it going back down. 1139 // This code tries to decide if the object is not on the ground and then pushing down
758 // Is this an angular force or both linear and angular?? 1140 /*
759 float distanceAboveGround = pos.Z - terrainHeight; 1141 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
760 if (distanceAboveGround > 2f) 1142 distanceAboveGround = VehiclePosition.Z - targetHeight;
1143 // Not colliding if the vehicle is off the ground
1144 if (!Prim.IsColliding)
761 { 1145 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1146 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1147 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
765 } 1148 }
766 // TODO: this calculation is all wrong. From the description at 1149 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1150 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1151 // has a decay factor. This says this force should
769 // be computed with a motor. 1152 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1153 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce); 1154 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
772 } 1155 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
773 #endregion // downForce 1156 */
774 1157
775 // If not changing some axis, reduce out velocity 1158 // Another approach is to measure if we're going up. If going up and not colliding,
776 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1159 // the vehicle is in the air. Fix that by pushing down.
777 m_newVelocity.X = 0; 1160 if (!Prim.IsColliding && VehicleVelocity.Z > 0.1)
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1161 {
779 m_newVelocity.Y = 0; 1162 // Get rid of any of the velocity vector that is pushing us up.
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1163 VehicleVelocity += new Vector3(0, 0, -VehicleVelocity.Z);
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 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
791
792 // Stuff new linear velocity into the vehicle
793 Prim.ForceVelocity = m_newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
795 1164
796 Vector3 totalDownForce = downForce + grav; 1165 // If we're pointed up into the air, we should nose down
797 if (totalDownForce != Vector3.Zero) 1166 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
798 { 1167 // The rotation around the Y axis is pitch up or down
799 Prim.AddForce(totalDownForce * m_vehicleMass, false); 1168 if (pointingDirection.Y > 0.01f)
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); 1169 {
1170 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1171 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1172 // Rotate into world coordinates and apply to vehicle
1173 angularCorrectionVector *= VehicleOrientation;
1174 VehicleAddAngularForce(angularCorrectionVector);
1175 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1176 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1177 }
1178 else
1179 {
1180 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2}",
1181 Prim.LocalID, VehicleVelocity, pointingDirection);
1182 }
1183 }
801 } 1184 }
1185 }
802 1186
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1187 private void ApplyGravity(float pTimeStep)
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); 1188 {
1189 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1190 VehicleAddForce(appliedGravity);
805 1191
806 } // end MoveLinear() 1192 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},appliedForce-{2}",
1193 Prim.LocalID, m_VehicleGravity, appliedGravity);
1194 }
807 1195
808 // ======================================================================= 1196 // =======================================================================
1197 // =======================================================================
809 // Apply the effect of the angular motor. 1198 // Apply the effect of the angular motor.
1199 // The 'contribution' is how much angular correction velocity each function wants.
1200 // All the contributions are added together and the resulting velocity is
1201 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1202 private void MoveAngular(float pTimestep)
811 { 1203 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1204 // The user wants this many radians per second angular change?
813 // m_angularMotorApply // application frame counter 1205 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down) 1206
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 1207 // ==================================================================
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 1208 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
817 // m_angularFrictionTimescale // body angular velocity decay rate 1209 // This flag prevents linear deflection parallel to world z-axis. This is useful
818 // m_lastAngularVelocity // what was last applied to body 1210 // for preventing ground vehicles with large linear deflection, like bumper cars,
819 1211 // from climbing their linear deflection into the sky.
820 if (m_angularMotorDirection.LengthSquared() > 0.0001) 1212 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
821 { 1213 // TODO: This is here because this is where ODE put it but documentation says it
822 Vector3 origVel = m_angularMotorVelocity; 1214 // is a linear effect. Where should this check go?
823 Vector3 origDir = m_angularMotorDirection; 1215 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
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 { 1216 {
836 m_angularMotorVelocity = Vector3.Zero; 1217 angularMotorContribution.X = 0f;
1218 angularMotorContribution.Y = 0f;
1219 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
837 } 1220 }
838 1221
839 #region Vertical attactor 1222 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
840 1223
841 Vector3 vertattr = Vector3.Zero; 1224 Vector3 deflectionContribution = ComputeAngularDeflection();
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844 1225
845 // If vertical attaction timescale is reasonable and we applied an angular force last time... 1226 Vector3 bankingContribution = ComputeAngularBanking();
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 1227
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y 1228 // ==================================================================
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X. 1229 m_lastVertAttractor = verticalAttractionContribution;
873 // Z is not changed.
874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877 1230
878 // scaling appears better usingsquare-law 1231 m_lastAngularVelocity = angularMotorContribution
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity; 1232 + verticalAttractionContribution
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 1233 + deflectionContribution
881 vertattr.X += bounce * angularVelocity.X; 1234 + bankingContribution;
882 vertattr.Y += bounce * angularVelocity.Y;
883
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
886
887 }
888 #endregion // Vertical attactor
889 1235
890 #region Deflection 1236 // Add of the above computation are made relative to vehicle coordinates.
1237 // Convert to world coordinates.
1238 m_lastAngularVelocity *= VehicleOrientation;
891 1239
892 if (m_angularDeflectionEfficiency != 0) 1240 // ==================================================================
1241 // Apply the correction velocity.
1242 // TODO: Should this be applied as an angular force (torque)?
1243 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
893 { 1244 {
894 // Compute a scaled vector that points in the preferred axis (X direction) 1245 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 1246
912 #region Banking 1247 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
913 1248 Prim.LocalID,
914 if (m_bankingEfficiency != 0) 1249 angularMotorContribution, verticalAttractionContribution,
1250 bankingContribution, deflectionContribution,
1251 m_lastAngularVelocity
1252 );
1253 }
1254 else
915 { 1255 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1256 // The vehicle is not adding anything angular wise.
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1257 VehicleRotationalVelocity = Vector3.Zero;
918 //Changes which way it banks in and out of turns 1258 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 } 1259 }
963 1260
964 #endregion 1261 // ==================================================================
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 1262 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1263 if (m_linearMotorOffset != Vector3.Zero)
975 { 1264 {
@@ -985,8 +1274,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1274 //
986 // The torque created is the linear velocity crossed with the offset 1275 // The torque created is the linear velocity crossed with the offset
987 1276
988 // NOTE: this computation does should be in the linear section 1277 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1278 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1279 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1280 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1281 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1284,185 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1284 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1285 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1286 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1287
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1288 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1289 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1290 }
1002 1291
1003 #endregion 1292 }
1293 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1294 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1295 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1296 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1297 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1298 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1299 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1300 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1301 public Vector3 ComputeAngularVerticalAttraction()
1302 {
1303 Vector3 ret = Vector3.Zero;
1004 1304
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1305 // If vertical attaction timescale is reasonable
1306 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1006 { 1307 {
1007 m_lastAngularVelocity.X = 0; 1308 // Take a vector pointing up and convert it from world to vehicle relative coords.
1008 m_lastAngularVelocity.Y = 0; 1309 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1310
1311 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1312 // is now:
1313 // leaning to one side: rotated around the X axis with the Y value going
1314 // from zero (nearly straight up) to one (completely to the side)) or
1315 // leaning front-to-back: rotated around the Y axis with the value of X being between
1316 // zero and one.
1317 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1318
1319 // Y error means needed rotation around X axis and visa versa.
1320 // Since the error goes from zero to one, the asin is the corresponding angle.
1321 ret.X = (float)Math.Asin(verticalError.Y);
1322 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1323 ret.Y = -(float)Math.Asin(verticalError.X);
1324
1325 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1326 if (verticalError.Z < 0f)
1327 {
1328 ret.X += PIOverFour;
1329 ret.Y += PIOverFour;
1330 }
1331
1332 // 'ret' is now the necessary velocity to correct tilt in one second.
1333 // Correction happens over a number of seconds.
1334 Vector3 unscaledContrib = ret;
1335 ret /= m_verticalAttractionTimescale;
1336
1337 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1338 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1010 } 1339 }
1340 return ret;
1341 }
1342
1343 // Return the angular correction to correct the direction the vehicle is pointing to be
1344 // the direction is should want to be pointing.
1345 // The vehicle is moving in some direction and correct its orientation to it is pointing
1346 // in that direction.
1347 // TODO: implement reference frame.
1348 public Vector3 ComputeAngularDeflection()
1349 {
1350 Vector3 ret = Vector3.Zero;
1351
1352 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1353 // approximately the same X or Y correction. When added together (when contributions are combined)
1354 // this creates an over-correction and then wabbling as the target is overshot.
1355 // TODO: rethink how the different correction computations inter-relate.
1011 1356
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1357 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1013 { 1358 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1359 // The direction the vehicle is moving
1015 Prim.ZeroAngularMotion(true); 1360 Vector3 movingDirection = VehicleVelocity;
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1361 movingDirection.Normalize();
1362
1363 // If the vehicle is going backward, it is still pointing forward
1364 movingDirection *= Math.Sign(VehicleForwardSpeed);
1365
1366 // The direction the vehicle is pointing
1367 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1368 pointingDirection.Normalize();
1369
1370 // The difference between what is and what should be.
1371 Vector3 deflectionError = movingDirection - pointingDirection;
1372
1373 // Don't try to correct very large errors (not our job)
1374 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1375 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1376 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1377 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1378 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1379 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1380
1381 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1382
1383 // Scale the correction by recovery timescale and efficiency
1384 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1385 ret /= m_angularDeflectionTimescale;
1386
1387 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1388 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1389 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1390 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1017 } 1391 }
1018 else 1392 return ret;
1393 }
1394
1395 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1396 // is tipped around the X axis.
1397 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1398 // The vertical attractor feature must be enabled in order for the banking behavior to
1399 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1400 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1401 // of the yaw effect will be proportional to the
1402 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1403 // velocity along its preferred axis of motion.
1404 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1405 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1406 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1407 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1408 // Negating the banking coefficient will make it so that the vehicle leans to the
1409 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1410 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1411 // banking vehicles do what you want rather than what the laws of physics allow.
1412 // For example, consider a real motorcycle...it must be moving forward in order for
1413 // it to turn while banking, however video-game motorcycles are often configured
1414 // to turn in place when at a dead stop--because they are often easier to control
1415 // that way using the limited interface of the keyboard or game controller. The
1416 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1417 // banking by functioning as a slider between a banking that is correspondingly
1418 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1419 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1420 // to "dynamic" where the banking is also proportional to its velocity along its
1421 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1422 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1423 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1424 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1425 // make a sluggish vehicle by giving it a timescale of several seconds.
1426 public Vector3 ComputeAngularBanking()
1427 {
1428 Vector3 ret = Vector3.Zero;
1429
1430 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1431 {
1020 // Apply to the body. 1432 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1433 // As the vehicle rolls to the right or left, the Y value will increase from
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1434 // zero (straight up) to 1 or -1 (full tilt right or left)
1023 // velocity needs to be scaled by the timestep. 1435 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1436
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1437 // Figure out the yaw value for this much roll.
1026 1438 // Squared because that seems to give a good value
1027 // Decay the angular movement for next time 1439 float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1440
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1441 // actual error = static turn error + dynamic turn error
1030 1442 float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed;
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1443
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1444 // TODO: the banking effect should not go to infinity but what to limit it to?
1445 mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
1446
1447 // Build the force vector to change rotation from what it is to what it should be
1448 ret.Z = -mixedYawAngle;
1449
1450 // Don't do it all at once.
1451 ret /= m_bankingTimescale;
1452
1453 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1454 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, ret);
1033 } 1455 }
1034 } //end MoveAngular 1456 return ret;
1457 }
1035 1458
1459 // This is from previous instantiations of XXXDynamics.cs.
1460 // Applies roll reference frame.
1461 // TODO: is this the right way to separate the code to do this operation?
1462 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1463 internal void LimitRotation(float timestep)
1037 { 1464 {
1038 Quaternion rotq = Prim.ForceOrientation; 1465 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1466 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1467 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1468 {
@@ -1063,12 +1490,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1490 }
1064 if (rotq != m_rot) 1491 if (rotq != m_rot)
1065 { 1492 {
1066 Prim.ForceOrientation = m_rot; 1493 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1494 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1495 }
1069 1496
1070 } 1497 }
1071 1498
1499 private float ClampInRange(float low, float val, float high)
1500 {
1501 return Math.Max(low, Math.Min(val, high));
1502 // return Utils.Clamp(val, low, high);
1503 }
1504
1072 // Invoke the detailed logger and output something if it's enabled. 1505 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1506 private void VDetailLog(string msg, params Object[] args)
1074 { 1507 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..cbd160f 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]";
@@ -47,7 +56,7 @@ public abstract class BSLinkset
47 { 56 {
48 BSLinkset ret = null; 57 BSLinkset ret = null;
49 58
50 switch ((int)physScene.Params.linksetImplementation) 59 switch ((int)BSParam.LinksetImplementation)
51 { 60 {
52 case (int)LinksetImplementation.Constraint: 61 case (int)LinksetImplementation.Constraint:
53 ret = new BSLinksetConstraints(physScene, parent); 62 ret = new BSLinksetConstraints(physScene, parent);
@@ -87,22 +96,8 @@ 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 public float LinksetMass { get; protected set; }
99 public float LinksetMass
100 {
101 get
102 {
103 return m_mass;
104 }
105 }
106 101
107 public virtual bool LinksetIsColliding { get { return false; } } 102 public virtual bool LinksetIsColliding { get { return false; } }
108 103
@@ -116,7 +111,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 111 get { return ComputeLinksetGeometricCenter(); }
117 } 112 }
118 113
119 protected void Initialize(BSScene scene, BSPhysObject parent) 114 protected BSLinkset(BSScene scene, BSPhysObject parent)
120 { 115 {
121 // A simple linkset of one (no children) 116 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 117 LinksetID = m_nextLinksetID++;
@@ -126,7 +121,8 @@ public abstract class BSLinkset
126 PhysicsScene = scene; 121 PhysicsScene = scene;
127 LinksetRoot = parent; 122 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 123 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass; 124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
130 } 126 }
131 127
132 // Link to a linkset where the child knows the parent. 128 // Link to a linkset where the child knows the parent.
@@ -140,7 +136,7 @@ public abstract class BSLinkset
140 // Don't add the root to its own linkset 136 // Don't add the root to its own linkset
141 if (!IsRoot(child)) 137 if (!IsRoot(child))
142 AddChildToLinkset(child); 138 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass(); 139 LinksetMass = ComputeLinksetMass();
144 } 140 }
145 return this; 141 return this;
146 } 142 }
@@ -156,13 +152,15 @@ public abstract class BSLinkset
156 if (IsRoot(child)) 152 if (IsRoot(child))
157 { 153 {
158 // Cannot remove the root from a linkset. 154 // Cannot remove the root from a linkset.
155 child.PositionDisplacement = OMV.Vector3.Zero;
159 return this; 156 return this;
160 } 157 }
161 RemoveChildFromLinkset(child); 158 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass(); 159 LinksetMass = ComputeLinksetMass();
163 } 160 }
164 161
165 // The child is down to a linkset of just itself 162 // The child is down to a linkset of just itself
163 child.PositionDisplacement = OMV.Vector3.Zero;
166 return BSLinkset.Factory(PhysicsScene, child); 164 return BSLinkset.Factory(PhysicsScene, child);
167 } 165 }
168 166
@@ -219,7 +217,7 @@ public abstract class BSLinkset
219 // I am the root of a linkset and a new child is being added 217 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 218 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 219 protected abstract void AddChildToLinkset(BSPhysObject child);
222 220
223 // I am the root of a linkset and one of my children is being removed. 221 // 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. 222 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 223 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@@ -227,7 +225,14 @@ public abstract class BSLinkset
227 // When physical properties are changed the linkset needs to recalculate 225 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 226 // its internal properties.
229 // May be called at runtime or taint-time. 227 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 228 public virtual void Refresh(BSPhysObject requestor)
229 {
230 LinksetMass = ComputeLinksetMass();
231 }
232
233 // Flag denoting the linkset is in the process of being rebuilt.
234 // Used to know not the schedule a rebuild in the middle of a rebuild.
235 protected bool Rebuilding { get; set; }
231 236
232 // The object is going dynamic (physical). Do any setup necessary 237 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 238 // for a dynamic linkset.
@@ -245,8 +250,9 @@ public abstract class BSLinkset
245 250
246 // Called when a parameter update comes from the physics engine for any object 251 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 252 // of the linkset is received.
253 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 254 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 255 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
250 256
251 // Routine used when rebuilding the body of the root of the linkset 257 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 258 // Destroy all the constraints have have been made to root.
@@ -306,7 +312,7 @@ public abstract class BSLinkset
306 312
307 foreach (BSPhysObject bp in m_children) 313 foreach (BSPhysObject bp in m_children)
308 { 314 {
309 com += bp.Position * bp.RawMass; 315 com += bp.Position;
310 } 316 }
311 com /= (m_children.Count + 1); 317 com /= (m_children.Count + 1);
312 } 318 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..2dc89b5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,64 @@ 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 int Index;
44 public OMV.Vector3 OffsetFromRoot;
45 public OMV.Vector3 OffsetFromCenterOfMass;
46 public OMV.Quaternion OffsetRot;
47 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
48 {
49 Index = indx;
50 OffsetFromRoot = p;
51 OffsetFromCenterOfMass = p;
52 OffsetRot = r;
53 }
54 public override void Clear()
55 {
56 Index = 0;
57 OffsetFromRoot = OMV.Vector3.Zero;
58 OffsetFromCenterOfMass = OMV.Vector3.Zero;
59 OffsetRot = OMV.Quaternion.Identity;
60 }
61 public override string ToString()
62 {
63 StringBuilder buff = new StringBuilder();
64 buff.Append("<i=");
65 buff.Append(Index.ToString());
66 buff.Append(",p=");
67 buff.Append(OffsetFromRoot.ToString());
68 buff.Append(",m=");
69 buff.Append(OffsetFromCenterOfMass.ToString());
70 buff.Append(",r=");
71 buff.Append(OffsetRot.ToString());
72 buff.Append(">");
73 return buff.ToString();
74 }
75};
76
35public sealed class BSLinksetCompound : BSLinkset 77public sealed class BSLinksetCompound : BSLinkset
36{ 78{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 79 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 80
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 81 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 82 {
41 base.Initialize(scene, parent);
42 } 83 }
43 84
44 // For compound implimented linksets, if there are children, use compound shape for the root. 85 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 86 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 87 {
88 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 89 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 90 if (IsRoot(requestor) && HasAnyChildren)
49 { 91 {
@@ -55,27 +97,33 @@ public sealed class BSLinksetCompound : BSLinkset
55 97
56 // When physical properties are changed the linkset needs to recalculate 98 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 99 // 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) 100 public override void Refresh(BSPhysObject requestor)
61 { 101 {
62 // External request for Refresh (from BSPrim) is not necessary 102 base.Refresh(requestor);
63 // InternalRefresh(requestor); 103
104 // Something changed so do the rebuilding thing
105 // ScheduleRebuild();
64 } 106 }
65 107
66 private void InternalRefresh(BSPhysObject requestor) 108 // Schedule a refresh to happen after all the other taint processing.
109 private void ScheduleRebuild(BSPhysObject requestor)
67 { 110 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 111 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}",
69 // Queue to happen after all the other taint processing 112 requestor.LocalID, Rebuilding, HasAnyChildren);
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 113 // When rebuilding, it is possible to set properties that would normally require a rebuild.
114 // If already rebuilding, don't request another rebuild.
115 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
116 if (!Rebuilding && HasAnyChildren)
71 { 117 {
72 if (IsRoot(requestor) && HasAnyChildren) 118 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 119 {
74 }); 120 if (HasAnyChildren)
121 RecomputeLinksetCompound();
122 });
123 }
75 } 124 }
76 125
77 // The object is going dynamic (physical). Do any setup necessary 126 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset 127 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 128 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 129 // Return 'true' if any properties updated on the passed object.
@@ -84,12 +132,22 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 132 {
85 bool ret = false; 133 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 134 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 135 if (IsRoot(child))
136 {
137 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
138 ScheduleRebuild(LinksetRoot);
139 }
140 else
88 { 141 {
89 // Physical children are removed from the world as the shape ofthe root compound 142 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 143 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 144 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 145 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
146 // We don't want collisions from the old linkset children.
147 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
148
149 child.PhysBody.collisionType = CollisionType.LinksetChild;
150
93 ret = true; 151 ret = true;
94 } 152 }
95 return ret; 153 return ret;
@@ -104,33 +162,45 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 162 {
105 bool ret = false; 163 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 164 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 165 if (IsRoot(child))
166 {
167 ScheduleRebuild(LinksetRoot);
168 }
169 else
108 { 170 {
109 // The non-physical children can come back to life. 171 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 172 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 173
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 174 child.PhysBody.collisionType = CollisionType.LinksetChild;
175
176 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
177 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 178 ret = true;
114 } 179 }
115 return ret; 180 return ret;
116 } 181 }
117 182
118 // Called at taint-time!! 183 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
119 public override void UpdateProperties(BSPhysObject updated) 184 // Called at taint-time.
120 { 185 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 { 186 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 187 // The user moving a child around requires the rebuilding of the linkset compound shape
188 // One problem is this happens when a border is crossed -- the simulator implementation
189 // is to store the position into the group which causes the move of the object
190 // but it also means all the child positions get updated.
191 // What would cause an unnecessary rebuild so we make sure the linkset is in a
192 // region before bothering to do a rebuild.
193 if (!IsRoot(updated)
194 && !physicalUpdate
195 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
196 {
197 // TODO: replace this with are calculation of the child prim's orientation and pos.
198 // TODO: for the moment, don't rebuild the compound shape.
199 // This is often just the car turning its wheels. When we can just reorient the one
200 // member shape of the compound shape, the overhead of rebuilding won't be a problem.
201 // updated.LinksetInfo = null;
202 // ScheduleRebuild(updated);
203 }
134 } 204 }
135 205
136 // Routine called when rebuilding the body of some member of the linkset. 206 // Routine called when rebuilding the body of some member of the linkset.
@@ -142,24 +212,62 @@ public sealed class BSLinksetCompound : BSLinkset
142 bool ret = false; 212 bool ret = false;
143 213
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 214 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 215 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
146 216
147 if (!IsRoot(child)) 217 if (!IsRoot(child))
148 { 218 {
149 // Cause the current shape to be freed and the new one to be built. 219 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 220 // its position in the linkset.
151 ret = true; 221 RecomputeChildWorldPosition(child, true);
152 } 222 }
153 223
224 // Cannot schedule a refresh/rebuild here because this routine is called when
225 // the linkset is being rebuilt.
226 // InternalRefresh(LinksetRoot);
227
154 return ret; 228 return ret;
155 } 229 }
156 230
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 231 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 232 // this routine will restore the removed constraints.
159 // Called at taint-time!! 233 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 234 public override void RestoreBodyDependencies(BSPrim child)
161 { 235 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 236 }
237
238 // When the linkset is built, the child shape is added to the compound shape relative to the
239 // root shape. The linkset then moves around but this does not move the actual child
240 // prim. The child prim's location must be recomputed based on the location of the root shape.
241 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
242 {
243 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
244 if (lci != null)
245 {
246 if (inTaintTime)
247 {
248 OMV.Vector3 oldPos = child.RawPosition;
249 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
250 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
251 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
252 child.LocalID, oldPos, lci, child.RawPosition);
253 }
254 else
255 {
256 // TaintedObject is not used here so the raw position is set now and not at taint-time.
257 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
258 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
259 }
260 }
261 else
262 {
263 // This happens when children have been added to the linkset but the linkset
264 // has not been constructed yet. So like, at taint time, adding children to a linkset
265 // and then changing properties of the children (makePhysical, for instance)
266 // but the post-print action of actually rebuilding the linkset has not yet happened.
267 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
268 // LogHeader, child.LocalID);
269 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
270 }
163 } 271 }
164 272
165 // ================================================================ 273 // ================================================================
@@ -174,24 +282,25 @@ public sealed class BSLinksetCompound : BSLinkset
174 282
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 283 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 284
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 285 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 286 ScheduleRebuild(child);
179 } 287 }
180 return; 288 return;
181 } 289 }
182 290
183 // Remove the specified child from the linkset. 291 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 292 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 293 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 294 {
187 if (m_children.Remove(child)) 295 if (m_children.Remove(child))
188 { 296 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 297 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 298 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 299 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 300 child.LocalID, child.PhysBody.AddrString);
193 301
194 // Cause the child's body to be rebuilt and thus restored to normal operation 302 // Cause the child's body to be rebuilt and thus restored to normal operation
303 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 304 child.ForceBodyShapeRebuild(false);
196 305
197 if (!HasAnyChildren) 306 if (!HasAnyChildren)
@@ -201,8 +310,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 310 }
202 else 311 else
203 { 312 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 313 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 314 ScheduleRebuild(child);
206 } 315 }
207 } 316 }
208 return; 317 return;
@@ -213,63 +322,116 @@ public sealed class BSLinksetCompound : BSLinkset
213 // Constraint linksets are rebuilt every time. 322 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart. 323 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!! 324 // Called at taint time!!
325 private bool disableCOM = true; // disable until we get this debugged
216 private void RecomputeLinksetCompound() 326 private void RecomputeLinksetCompound()
217 { 327 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 328 try
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 { 329 {
227 if (!IsRoot(cPrim)) 330 // Suppress rebuilding while rebuilding
331 Rebuilding = true;
332
333 // Cause the root shape to be rebuilt as a compound object with just the root in it
334 LinksetRoot.ForceBodyShapeRebuild(true);
335
336 // The center of mass for the linkset is the geometric center of the group.
337 // Compute a displacement for each component so it is relative to the center-of-mass.
338 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
339 OMV.Vector3 centerOfMass;
340 OMV.Vector3 centerDisplacement = OMV.Vector3.Zero;
341 if (disableCOM) // DEBUG DEBUG
342 { // DEBUG DEBUG
343 centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
344 LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
345 } // DEBUG DEBUG
346 else
228 { 347 {
229 // Each child position and rotation is given relative to the root. 348 centerOfMass = ComputeLinksetGeometricCenter();
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 349 centerDisplacement = centerOfMass - LinksetRoot.RawPosition;
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233 350
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 351 // Since we're displacing the center of the shape, we need to move the body in the world
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 352 LinksetRoot.PositionDisplacement = centerDisplacement;
236 353
237 if (cPrim.PhysShape.isNativeShape) 354 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
238 { 355 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
239 // Native shapes are not shared so we need to create a new one. 356 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
240 // A mesh or hull is created because scale is not available on a native shape. 357 }
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 358
242 BulletShape saveShape = cPrim.PhysShape; 359 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 360 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); 361
245 BulletShape newShape = cPrim.PhysShape; 362 // Add a shape for each of the other children in the linkset
246 cPrim.PhysShape = saveShape; 363 int memberIndex = 1;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); 364 ForEachMember(delegate(BSPhysObject cPrim)
248 } 365 {
249 else 366 if (!IsRoot(cPrim))
250 { 367 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 368 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 369 // This info is saved in the child prim so the relationship does not
370 // change over time and the new child position can be computed
371 // when the linkset is being disassembled (the linkset may have moved).
372 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
373 if (lci == null)
253 { 374 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 375 // Each child position and rotation is given relative to the center-of-mass.
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 376 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
377 OMV.Vector3 displacementFromRoot = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
378 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
379 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
380
381 // Save relative position for recomputing child's world position after moving linkset.
382 lci = new BSLinksetCompoundInfo(memberIndex, displacementFromCOM, displacementRot);
383 lci.OffsetFromRoot = displacementFromRoot;
384 cPrim.LinksetInfo = lci;
385 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 386 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262 387
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 388 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
264 float linksetMass = LinksetMass; 389 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266 390
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 391 if (cPrim.PhysShape.isNativeShape)
392 {
393 // A native shape is turning into a hull collision shape because native
394 // shapes are not shared so we have to hullify it so it will be tracked
395 // and freed at the correct time. This also solves the scaling problem
396 // (native shapes scaled but hull/meshes are assumed to not be).
397 // TODO: decide of the native shape can just be used in the compound shape.
398 // Use call to CreateGeomNonSpecial().
399 BulletShape saveShape = cPrim.PhysShape;
400 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
401 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
402 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
403 BulletShape newShape = cPrim.PhysShape;
404 cPrim.PhysShape = saveShape;
405 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
406 }
407 else
408 {
409 // For the shared shapes (meshes and hulls), just use the shape in the child.
410 // The reference count added here will be decremented when the compound shape
411 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
412 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
413 {
414 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
415 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
416 }
417 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
418 }
419 lci.Index = memberIndex;
420 memberIndex++;
421 }
422 return false; // 'false' says to move onto the next child in the list
423 });
268 424
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 425 // With all of the linkset packed into the root prim, it has the mass of everyone.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 426 LinksetMass = ComputeLinksetMass();
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 427 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
428 }
429 finally
430 {
431 Rebuilding = false;
432 }
272 433
434 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 435 }
274} 436}
275} \ No newline at end of file 437} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..d0b2a56 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
@@ -47,12 +46,17 @@ public sealed class BSLinksetConstraints : BSLinkset
47 // refresh will happen once after all the other taints are applied. 46 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor) 47 public override void Refresh(BSPhysObject requestor)
49 { 48 {
50 // Queue to happen after all the other taint processing 49 base.Refresh(requestor);
51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 50
52 { 51 if (HasAnyChildren && IsRoot(requestor))
53 if (HasAnyChildren && IsRoot(requestor)) 52 {
54 RecomputeLinksetConstraints(); 53 // Queue to happen after all the other taint processing
55 }); 54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 {
56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints();
58 });
59 }
56 } 60 }
57 61
58 // The object is going dynamic (physical). Do any setup necessary 62 // The object is going dynamic (physical). Do any setup necessary
@@ -79,23 +83,11 @@ public sealed class BSLinksetConstraints : BSLinkset
79 } 83 }
80 84
81 // Called at taint-time!! 85 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated) 86 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
83 { 87 {
84 // Nothing to do for constraints on property updates 88 // Nothing to do for constraints on property updates
85 } 89 }
86 90
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. 91 // 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 92 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step. 93 // up to rebuild the constraints before the next simulation step.
@@ -106,7 +98,7 @@ public sealed class BSLinksetConstraints : BSLinkset
106 bool ret = false; 98 bool ret = false;
107 99
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
110 102
111 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
112 { 104 {
@@ -155,8 +147,8 @@ public sealed class BSLinksetConstraints : BSLinkset
155 147
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 148 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID, 149 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), 150 rootx.LocalID, rootx.PhysBody.AddrString,
159 childx.LocalID, childx.PhysBody.ptr.ToString("X")); 151 childx.LocalID, childx.PhysBody.AddrString);
160 152
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 153 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 { 154 {
@@ -195,8 +187,8 @@ public sealed class BSLinksetConstraints : BSLinkset
195 187
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 188 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID, 189 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 190 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), 191 childPrim.LocalID, childPrim.PhysBody.AddrString,
200 rootPrim.Position, childPrim.Position, midPoint); 192 rootPrim.Position, childPrim.Position, midPoint);
201 193
202 // create a constraint that allows no freedom of movement between the two objects 194 // create a constraint that allows no freedom of movement between the two objects
@@ -239,14 +231,14 @@ public sealed class BSLinksetConstraints : BSLinkset
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 231 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240 232
241 // tweek the constraint to increase stability 233 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); 234 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), 235 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 236 BSParam.LinkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 237 BSParam.LinkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 238 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) 239 if (BSParam.LinkConstraintSolverIterations != 0f)
248 { 240 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 241 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
250 } 242 }
251 return constrain; 243 return constrain;
252 } 244 }
@@ -260,14 +252,14 @@ public sealed class BSLinksetConstraints : BSLinkset
260 bool ret = false; 252 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 253 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID, 254 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 255 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); 256 childPrim.LocalID, childPrim.PhysBody.AddrString);
265 257
266 // Find the constraint for this link and get rid of it from the overall collection and from my list 258 // Find the constraint for this link and get rid of it from the overall collection and from my list
267 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) 259 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 { 260 {
269 // Make the child refresh its location 261 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); 262 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
271 ret = true; 263 ret = true;
272 } 264 }
273 265
@@ -292,20 +284,17 @@ public sealed class BSLinksetConstraints : BSLinkset
292 private void RecomputeLinksetConstraints() 284 private void RecomputeLinksetConstraints()
293 { 285 {
294 float linksetMass = LinksetMass; 286 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 287 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
296 288
297 // DEBUG: see of inter-linkset collisions are causing problems
298 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
299 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
300 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", 289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); 290 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
302 291
303 foreach (BSPhysObject child in m_children) 292 foreach (BSPhysObject child in m_children)
304 { 293 {
305 // A child in the linkset physically shows the mass of the whole linkset. 294 // A child in the linkset physically shows the mass of the whole linkset.
306 // This allows Bullet to apply enough force on the child to move the whole linkset. 295 // This allows Bullet to apply enough force on the child to move the whole linkset.
307 // (Also do the mass stuff before recomputing the constraint so mass is not zero.) 296 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass); 297 child.UpdatePhysicalMassProperties(linksetMass, true);
309 298
310 BSConstraint constrain; 299 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 300 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
@@ -315,11 +304,7 @@ public sealed class BSLinksetConstraints : BSLinkset
315 } 304 }
316 constrain.RecomputeConstraintVariables(linksetMass); 305 constrain.RecomputeConstraintVariables(linksetMass);
317 306
318 // DEBUG: see of inter-linkset collisions are causing problems 307 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
319 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
320 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
321
322 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
323 } 308 }
324 309
325 } 310 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..92d62ff
--- /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",3.5f, 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.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 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",3.5f, 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..6d0db2e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,467 @@
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; 32using OpenSim.Framework;
33 CurrentValueReductionTimescale = frictionTimeScale; 33
34 Efficiency = efficiency; 34namespace OpenSim.Region.Physics.BulletSPlugin
35 } 35{
36 public void SetCurrent(Vector3 current) 36public abstract class BSMotor
37 { 37{
38 CurrentValue = current; 38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 } 39 public const float Infinite = 12345.6f;
40 public void SetTarget(Vector3 target) 40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41 { 41
42 TargetValue = target; 42 public BSMotor(string useName)
43 } 43 {
44 public Vector3 Step(float timeStep) 44 UseName = useName;
45 { 45 PhysicsScene = null;
46 if (CurrentValue.LengthSquared() > 0.001f) 46 Enabled = true;
47 { 47 }
48 // Vector3 origDir = Target; // DEBUG 48 public virtual bool Enabled { get; set; }
49 // Vector3 origVel = CurrentValue; // DEBUG 49 public virtual void Reset() { }
50 50 public virtual void Zero() { }
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete 51 public virtual void GenerateTestOutput(float timeStep) { }
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; 52
53 CurrentValue += addAmount; 53 // A name passed at motor creation for easily identifyable debugging messages.
54 54 public string UseName { get; private set; }
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 55
56 TargetValue *= (1f - decayFactor); 56 // Used only for outputting debug information. Might not be set so check for null.
57 57 public BSScene PhysicsScene { get; set; }
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; 58 protected void MDetailLog(string msg, params Object[] parms)
59 CurrentValue *= (Vector3.One - frictionFactor); 59 {
60 } 60 if (PhysicsScene != null)
61 else 61 {
62 { 62 PhysicsScene.DetailLog(msg, parms);
63 // if what remains of direction is very small, zero it. 63 }
64 TargetValue = Vector3.Zero; 64 }
65 CurrentValue = Vector3.Zero; 65}
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// This motor will "zero itself" over time in that the targetValue will
71} 71// decay to zero and the currentValue will follow it to that zero.
72 72// The overall effect is for the returned correction value to go from large
73public class BSFMotor : BSMotor 73// values (the total difference between current and target minus friction)
74{ 74// to small and eventually zero values.
75 public float TimeScale { get; set; } 75// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
76 public float DecayTimeScale { get; set; } 76
77 public float Friction { get; set; } 77// For instance, if something is moving at speed X and the desired speed is Y,
78 public float Efficiency { get; set; } 78// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
79 79// values of CurrentValue are returned that approach the TargetValue.
80 public float Target { get; private set; } 80// The feature of decaying TargetValue is so vehicles will eventually
81 public float CurrentValue { get; private set; } 81// come to a stop rather than run forever. This can be disabled by
82 82// setting TargetValueDecayTimescale to 'infinite'.
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) 83// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
84 { 84public class BSVMotor : BSMotor
85 } 85{
86 public void SetCurrent(float target) 86 // public Vector3 FrameOfReference { get; set; }
87 { 87 // public Vector3 Offset { get; set; }
88 } 88
89 public void SetTarget(float target) 89 public virtual float TimeScale { get; set; }
90 { 90 public virtual float TargetValueDecayTimeScale { get; set; }
91 } 91 public virtual Vector3 FrictionTimescale { get; set; }
92 public float Step(float timeStep) 92 public virtual float Efficiency { get; set; }
93 { 93
94 return 0f; 94 public virtual float ErrorZeroThreshold { get; set; }
95 } 95
96} 96 public virtual Vector3 TargetValue { get; protected set; }
97public class BSPIDMotor : BSMotor 97 public virtual Vector3 CurrentValue { get; protected set; }
98{ 98 public virtual Vector3 LastError { get; protected set; }
99 // TODO: write and use this one 99
100 BSPIDMotor() 100 public virtual bool ErrorIsZero()
101 { 101 {
102 } 102 return ErrorIsZero(LastError);
103} 103 }
104} 104 public virtual bool ErrorIsZero(Vector3 err)
105 {
106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 }
108
109 public BSVMotor(string useName)
110 : base(useName)
111 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f;
117 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
119 : this(useName)
120 {
121 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero;
126 }
127 public void SetCurrent(Vector3 current)
128 {
129 CurrentValue = current;
130 }
131 public void SetTarget(Vector3 target)
132 {
133 TargetValue = target;
134 }
135 public override void Zero()
136 {
137 base.Zero();
138 CurrentValue = TargetValue = Vector3.Zero;
139 }
140
141 // Compute the next step and return the new current value
142 public virtual Vector3 Step(float timeStep)
143 {
144 if (!Enabled) return TargetValue;
145
146 Vector3 origTarget = TargetValue; // DEBUG
147 Vector3 origCurrVal = CurrentValue; // DEBUG
148
149 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue;
151 if (!ErrorIsZero(error))
152 {
153 correction = Step(timeStep, error);
154
155 CurrentValue += correction;
156
157 // The desired value reduces to zero which also reduces the difference with current.
158 // If the decay time is infinite, don't decay at all.
159 float decayFactor = 0f;
160 if (TargetValueDecayTimeScale != BSMotor.Infinite)
161 {
162 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
163 TargetValue *= (1f - decayFactor);
164 }
165
166 // The amount we can correct the error is reduced by the friction
167 Vector3 frictionFactor = Vector3.Zero;
168 if (FrictionTimescale != BSMotor.InfiniteVector)
169 {
170 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
171 // Individual friction components can be 'infinite' so compute each separately.
172 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
173 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
174 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
175 frictionFactor *= timeStep;
176 CurrentValue *= (Vector3.One - frictionFactor);
177 }
178
179 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
183 BSScene.DetailLogZero, UseName,
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 }
187 else
188 {
189 // Difference between what we have and target is small. Motor is done.
190 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
193 }
194
195 return CurrentValue;
196 }
197 public virtual Vector3 Step(float timeStep, Vector3 error)
198 {
199 if (!Enabled) return Vector3.Zero;
200
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero;
203 if (!ErrorIsZero())
204 {
205 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount;
207 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
208 correctionAmount = error * timeStep;
209 else
210 correctionAmount = error / TimeScale * timeStep;
211
212 returnCorrection = correctionAmount;
213 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
214 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
215 }
216 return returnCorrection;
217 }
218
219 // The user sets all the parameters and calls this which outputs values until error is zero.
220 public override void GenerateTestOutput(float timeStep)
221 {
222 // maximum number of outputs to generate.
223 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
225 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
226 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
228 CurrentValue, TargetValue);
229
230 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
232 {
233 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238
239
240 }
241
242 public override string ToString()
243 {
244 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
245 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
246 }
247}
248
249// ============================================================================
250// ============================================================================
251public class BSFMotor : BSMotor
252{
253 public virtual float TimeScale { get; set; }
254 public virtual float TargetValueDecayTimeScale { get; set; }
255 public virtual float FrictionTimescale { get; set; }
256 public virtual float Efficiency { get; set; }
257
258 public virtual float ErrorZeroThreshold { get; set; }
259
260 public virtual float TargetValue { get; protected set; }
261 public virtual float CurrentValue { get; protected set; }
262 public virtual float LastError { get; protected set; }
263
264 public virtual bool ErrorIsZero()
265 {
266 return ErrorIsZero(LastError);
267 }
268 public virtual bool ErrorIsZero(float err)
269 {
270 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
271 }
272
273 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
274 : base(useName)
275 {
276 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
277 Efficiency = 1f;
278 FrictionTimescale = BSMotor.Infinite;
279 CurrentValue = TargetValue = 0f;
280 ErrorZeroThreshold = 0.01f;
281 }
282 public void SetCurrent(float current)
283 {
284 CurrentValue = current;
285 }
286 public void SetTarget(float target)
287 {
288 TargetValue = target;
289 }
290 public override void Zero()
291 {
292 base.Zero();
293 CurrentValue = TargetValue = 0f;
294 }
295
296 public virtual float Step(float timeStep)
297 {
298 if (!Enabled) return TargetValue;
299
300 float origTarget = TargetValue; // DEBUG
301 float origCurrVal = CurrentValue; // DEBUG
302
303 float correction = 0f;
304 float error = TargetValue - CurrentValue;
305 if (!ErrorIsZero(error))
306 {
307 correction = Step(timeStep, error);
308
309 CurrentValue += correction;
310
311 // The desired value reduces to zero which also reduces the difference with current.
312 // If the decay time is infinite, don't decay at all.
313 float decayFactor = 0f;
314 if (TargetValueDecayTimeScale != BSMotor.Infinite)
315 {
316 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
317 TargetValue *= (1f - decayFactor);
318 }
319
320 // The amount we can correct the error is reduced by the friction
321 float frictionFactor = 0f;
322 if (FrictionTimescale != BSMotor.Infinite)
323 {
324 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
325 // Individual friction components can be 'infinite' so compute each separately.
326 frictionFactor = 1f / FrictionTimescale;
327 frictionFactor *= timeStep;
328 CurrentValue *= (1f - frictionFactor);
329 }
330
331 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
332 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
333 timeStep, error, correction);
334 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
335 BSScene.DetailLogZero, UseName,
336 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
337 TargetValue, CurrentValue);
338 }
339 else
340 {
341 // Difference between what we have and target is small. Motor is done.
342 CurrentValue = TargetValue;
343 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
344 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
345 }
346
347 return CurrentValue;
348 }
349
350 public virtual float Step(float timeStep, float error)
351 {
352 if (!Enabled) return 0f;
353
354 LastError = error;
355 float returnCorrection = 0f;
356 if (!ErrorIsZero())
357 {
358 // correction = error / secondsItShouldTakeToCorrect
359 float correctionAmount;
360 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
361 correctionAmount = error * timeStep;
362 else
363 correctionAmount = error / TimeScale * timeStep;
364
365 returnCorrection = correctionAmount;
366 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
367 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
368 }
369 return returnCorrection;
370 }
371
372 public override string ToString()
373 {
374 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
375 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
376 }
377
378}
379
380// ============================================================================
381// ============================================================================
382// Proportional, Integral, Derivitive Motor
383// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
384public class BSPIDVMotor : BSVMotor
385{
386 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
387 public Vector3 proportionFactor { get; set; }
388 public Vector3 integralFactor { get; set; }
389 public Vector3 derivFactor { get; set; }
390
391 // The factors are vectors for the three dimensions. This is the proportional of each
392 // that is applied. This could be multiplied through the actual factors but it
393 // is sometimes easier to manipulate the factors and their mix separately.
394 // to
395 public Vector3 FactorMix;
396
397 // Arbritrary factor range.
398 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
399 public float EfficiencyHigh = 0.4f;
400 public float EfficiencyLow = 4.0f;
401
402 // Running integration of the error
403 Vector3 RunningIntegration { get; set; }
404
405 public BSPIDVMotor(string useName)
406 : base(useName)
407 {
408 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
409 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
410 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
411 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
412 RunningIntegration = Vector3.Zero;
413 LastError = Vector3.Zero;
414 }
415
416 public override void Zero()
417 {
418 base.Zero();
419 }
420
421 public override float Efficiency
422 {
423 get { return base.Efficiency; }
424 set
425 {
426 base.Efficiency = Util.Clamp(value, 0f, 1f);
427
428 // Compute factors based on efficiency.
429 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
430 // If efficiency is low (0f), use a factor value that overcorrects.
431 // TODO: might want to vary contribution of different factor depending on efficiency.
432 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
433 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
434
435 proportionFactor = new Vector3(factor, factor, factor);
436 integralFactor = new Vector3(factor, factor, factor);
437 derivFactor = new Vector3(factor, factor, factor);
438
439 MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
440 }
441 }
442
443 // Ignore Current and Target Values and just advance the PID computation on this error.
444 public override Vector3 Step(float timeStep, Vector3 error)
445 {
446 if (!Enabled) return Vector3.Zero;
447
448 // Add up the error so we can integrate over the accumulated errors
449 RunningIntegration += error * timeStep;
450
451 // A simple derivitive is the rate of change from the last error.
452 Vector3 derivitive = (error - LastError) * timeStep;
453 LastError = error;
454
455 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
456 Vector3 ret = error * timeStep * proportionFactor * FactorMix.X
457 + RunningIntegration * integralFactor * FactorMix.Y
458 + derivitive * derivFactor * FactorMix.Z
459 ;
460
461 MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}",
462 BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret);
463
464 return ret;
465 }
466}
467}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
new file mode 100755
index 0000000..862dbf6
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -0,0 +1,634 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48
49 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; }
51 public static float DeactivationTime { get; private set; }
52 public static float LinearSleepingThreshold { get; private set; }
53 public static float AngularSleepingThreshold { get; private set; }
54 public static float CcdMotionThreshold { get; private set; }
55 public static float CcdSweptSphereRadius { get; private set; }
56 public static float ContactProcessingThreshold { get; private set; }
57
58 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
59 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
60 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
61
62 public static float TerrainImplementation { get; private set; }
63 public static float TerrainFriction { get; private set; }
64 public static float TerrainHitFraction { get; private set; }
65 public static float TerrainRestitution { get; private set; }
66 public static float TerrainCollisionMargin { get; private set; }
67
68 // Avatar parameters
69 public static float AvatarFriction { get; private set; }
70 public static float AvatarStandingFriction { get; private set; }
71 public static float AvatarAlwaysRunFactor { get; private set; }
72 public static float AvatarDensity { get; private set; }
73 public static float AvatarRestitution { get; private set; }
74 public static float AvatarCapsuleWidth { get; private set; }
75 public static float AvatarCapsuleDepth { get; private set; }
76 public static float AvatarCapsuleHeight { get; private set; }
77 public static float AvatarContactProcessingThreshold { get; private set; }
78 public static float AvatarStepHeight { get; private set; }
79 public static float AvatarStepApproachFactor { get; private set; }
80 public static float AvatarStepForceFactor { get; private set; }
81
82 public static float VehicleAngularDamping { get; private set; }
83 public static float VehicleDebuggingEnabled { get; private set; }
84
85 public static float LinksetImplementation { get; private set; }
86 public static float LinkConstraintUseFrameOffset { get; private set; }
87 public static float LinkConstraintEnableTransMotor { get; private set; }
88 public static float LinkConstraintTransMotorMaxVel { get; private set; }
89 public static float LinkConstraintTransMotorMaxForce { get; private set; }
90 public static float LinkConstraintERP { get; private set; }
91 public static float LinkConstraintCFM { get; private set; }
92 public static float LinkConstraintSolverIterations { get; private set; }
93
94 public static float PID_D { get; private set; } // derivative
95 public static float PID_P { get; private set; } // proportional
96
97 // Various constants that come from that other virtual world that shall not be named
98 public const float MinGravityZ = -1f;
99 public const float MaxGravityZ = 28f;
100 public const float MinFriction = 0f;
101 public const float MaxFriction = 255f;
102 public const float MinDensity = 0f;
103 public const float MaxDensity = 22587f;
104 public const float MinRestitution = 0f;
105 public const float MaxRestitution = 1f;
106 public const float MaxAddForceMagnitude = 20000f;
107
108 // ===========================================================================
109 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
110 public delegate float ParamGet(BSScene scene);
111 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
112 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
113
114 public struct ParameterDefn
115 {
116 public string name; // string name of the parameter
117 public string desc; // a short description of what the parameter means
118 public float defaultValue; // default value if not specified anywhere else
119 public ParamUser userParam; // get the value from the configuration file
120 public ParamGet getter; // return the current value stored for this parameter
121 public ParamSet setter; // set the current value for this parameter
122 public SetOnObject onObject; // set the value on an object in the physical domain
123 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
124 {
125 name = n;
126 desc = d;
127 defaultValue = v;
128 userParam = u;
129 getter = g;
130 setter = s;
131 onObject = null;
132 }
133 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
134 {
135 name = n;
136 desc = d;
137 defaultValue = v;
138 userParam = u;
139 getter = g;
140 setter = s;
141 onObject = o;
142 }
143 }
144
145 // List of all of the externally visible parameters.
146 // For each parameter, this table maps a text name to getter and setters.
147 // To add a new externally referencable/settable parameter, add the paramter storage
148 // location somewhere in the program and make an entry in this table with the
149 // getters and setters.
150 // It is easiest to find an existing definition and copy it.
151 // Parameter values are floats. Booleans are converted to a floating value.
152 //
153 // A ParameterDefn() takes the following parameters:
154 // -- the text name of the parameter. This is used for console input and ini file.
155 // -- a short text description of the parameter. This shows up in the console listing.
156 // -- a default value (float)
157 // -- a delegate for fetching the parameter from the ini file.
158 // Should handle fetching the right type from the ini file and converting it.
159 // -- a delegate for getting the value as a float
160 // -- a delegate for setting the value from a float
161 // -- an optional delegate to update the value in the world. Most often used to
162 // push the new value to an in-world object.
163 //
164 // The single letter parameters for the delegates are:
165 // s = BSScene
166 // o = BSPhysObject
167 // p = string parameter name
168 // l = localID of referenced object
169 // v = value (float)
170 // cf = parameter configuration class (for fetching values from ini file)
171 private static ParameterDefn[] ParameterDefinitions =
172 {
173 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
174 ConfigurationParameters.numericTrue,
175 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
176 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
177 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
178 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
179 ConfigurationParameters.numericFalse,
180 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
181 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
182 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
183 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
184 ConfigurationParameters.numericTrue,
185 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
186 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
187 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
188
189 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
190 8f,
191 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
192 (s) => { return MeshLOD; },
193 (s,p,l,v) => { MeshLOD = v; } ),
194 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
195 16f,
196 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
197 (s) => { return MeshMegaPrimLOD; },
198 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
199 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
200 10f,
201 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
202 (s) => { return MeshMegaPrimThreshold; },
203 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
204 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
205 32f,
206 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
207 (s) => { return SculptLOD; },
208 (s,p,l,v) => { SculptLOD = v; } ),
209
210 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
211 10f,
212 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
213 (s) => { return (float)s.m_maxSubSteps; },
214 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
215 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
216 1f / 60f,
217 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
218 (s) => { return (float)s.m_fixedTimeStep; },
219 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
220 new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
221 55f,
222 (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); },
223 (s) => { return (float)s.NominalFrameRate; },
224 (s,p,l,v) => { s.NominalFrameRate = (int)v; } ),
225 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
226 2048f,
227 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
228 (s) => { return (float)s.m_maxCollisionsPerFrame; },
229 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
230 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
231 8000f,
232 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
233 (s) => { return (float)s.m_maxUpdatesPerFrame; },
234 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
235 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
236 500f,
237 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
238 (s) => { return (float)s.m_taintsToProcessPerStep; },
239 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
240 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
241 0.0001f,
242 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
243 (s) => { return (float)MinimumObjectMass; },
244 (s,p,l,v) => { MinimumObjectMass = v; } ),
245 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
246 10000.01f,
247 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
248 (s) => { return (float)MaximumObjectMass; },
249 (s,p,l,v) => { MaximumObjectMass = v; } ),
250
251 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
252 2200f,
253 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
254 (s) => { return (float)PID_D; },
255 (s,p,l,v) => { PID_D = v; } ),
256 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
257 900f,
258 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
259 (s) => { return (float)PID_P; },
260 (s,p,l,v) => { PID_P = v; } ),
261
262 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
263 0.2f,
264 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
265 (s) => { return s.UnmanagedParams[0].defaultFriction; },
266 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
267 new ParameterDefn("DefaultDensity", "Density for new objects" ,
268 10.000006836f, // Aluminum g/cm3
269 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
270 (s) => { return s.UnmanagedParams[0].defaultDensity; },
271 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
272 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
273 0f,
274 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
275 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
276 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
277 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
278 0.04f,
279 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
280 (s) => { return s.UnmanagedParams[0].collisionMargin; },
281 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
282 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
283 -9.80665f,
284 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
285 (s) => { return s.UnmanagedParams[0].gravity; },
286 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
287 (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ),
288
289
290 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
291 0f,
292 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
293 (s) => { return LinearDamping; },
294 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
295 (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ),
296 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
297 0f,
298 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
299 (s) => { return AngularDamping; },
300 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
301 (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ),
302 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
303 0.2f,
304 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
305 (s) => { return DeactivationTime; },
306 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
307 (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ),
308 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
309 0.8f,
310 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
311 (s) => { return LinearSleepingThreshold; },
312 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
313 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
314 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
315 1.0f,
316 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
317 (s) => { return AngularSleepingThreshold; },
318 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
319 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
320 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
321 0.3f, // set to zero to disable
322 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
323 (s) => { return CcdMotionThreshold; },
324 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
325 (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ),
326 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
327 0.2f,
328 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
329 (s) => { return CcdSweptSphereRadius; },
330 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
331 (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ),
332 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
333 0.1f,
334 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
335 (s) => { return ContactProcessingThreshold; },
336 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
337 (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ),
338
339 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
340 (float)BSTerrainPhys.TerrainImplementation.Mesh,
341 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
342 (s) => { return TerrainImplementation; },
343 (s,p,l,v) => { TerrainImplementation = v; } ),
344 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
345 0.3f,
346 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
347 (s) => { return TerrainFriction; },
348 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
349 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
350 0.8f,
351 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
352 (s) => { return TerrainHitFraction; },
353 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
354 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
355 0f,
356 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
357 (s) => { return TerrainRestitution; },
358 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
359 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
360 0.04f,
361 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
362 (s) => { return TerrainCollisionMargin; },
363 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
364
365 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
366 0.2f,
367 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
368 (s) => { return AvatarFriction; },
369 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
370 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
371 10.0f,
372 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
373 (s) => { return AvatarStandingFriction; },
374 (s,p,l,v) => { AvatarStandingFriction = v; } ),
375 new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
376 1.3f,
377 (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); },
378 (s) => { return AvatarAlwaysRunFactor; },
379 (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ),
380 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
381 3.5f,
382 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
383 (s) => { return AvatarDensity; },
384 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
385 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
386 0f,
387 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
388 (s) => { return AvatarRestitution; },
389 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
390 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
391 0.6f,
392 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
393 (s) => { return AvatarCapsuleWidth; },
394 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
395 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
396 0.45f,
397 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
398 (s) => { return AvatarCapsuleDepth; },
399 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
400 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
401 1.5f,
402 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
403 (s) => { return AvatarCapsuleHeight; },
404 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
405 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
406 0.1f,
407 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
408 (s) => { return AvatarContactProcessingThreshold; },
409 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
410 new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction",
411 0.3f,
412 (s,cf,p,v) => { AvatarStepHeight = cf.GetFloat(p, v); },
413 (s) => { return AvatarStepHeight; },
414 (s,p,l,v) => { AvatarStepHeight = v; } ),
415 new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
416 0.6f,
417 (s,cf,p,v) => { AvatarStepApproachFactor = cf.GetFloat(p, v); },
418 (s) => { return AvatarStepApproachFactor; },
419 (s,p,l,v) => { AvatarStepApproachFactor = v; } ),
420 new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
421 2.0f,
422 (s,cf,p,v) => { AvatarStepForceFactor = cf.GetFloat(p, v); },
423 (s) => { return AvatarStepForceFactor; },
424 (s,p,l,v) => { AvatarStepForceFactor = v; } ),
425
426 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
427 0.95f,
428 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
429 (s) => { return VehicleAngularDamping; },
430 (s,p,l,v) => { VehicleAngularDamping = v; } ),
431 new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
432 ConfigurationParameters.numericFalse,
433 (s,cf,p,v) => { VehicleDebuggingEnabled = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
434 (s) => { return VehicleDebuggingEnabled; },
435 (s,p,l,v) => { VehicleDebuggingEnabled = v; } ),
436
437 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
438 0f,
439 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
440 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
441 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
442 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
443 0f,
444 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
445 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
446 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
447 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
448 ConfigurationParameters.numericFalse,
449 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
450 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
451 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
452 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
453 ConfigurationParameters.numericFalse,
454 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
455 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
456 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
457 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
458 ConfigurationParameters.numericTrue,
459 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
460 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
461 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
462 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
463 ConfigurationParameters.numericTrue,
464 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
465 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
466 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
467 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
468 ConfigurationParameters.numericTrue,
469 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
470 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
471 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
472 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
473 0f, // zero says use Bullet default
474 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
475 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
476 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
477
478 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
479 (float)BSLinkset.LinksetImplementation.Compound,
480 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
481 (s) => { return LinksetImplementation; },
482 (s,p,l,v) => { LinksetImplementation = v; } ),
483 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
484 ConfigurationParameters.numericFalse,
485 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
486 (s) => { return LinkConstraintUseFrameOffset; },
487 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
488 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
489 ConfigurationParameters.numericTrue,
490 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
491 (s) => { return LinkConstraintEnableTransMotor; },
492 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
493 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
494 5.0f,
495 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
496 (s) => { return LinkConstraintTransMotorMaxVel; },
497 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
498 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
499 0.1f,
500 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
501 (s) => { return LinkConstraintTransMotorMaxForce; },
502 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
503 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
504 0.1f,
505 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
506 (s) => { return LinkConstraintCFM; },
507 (s,p,l,v) => { LinkConstraintCFM = v; } ),
508 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
509 0.1f,
510 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
511 (s) => { return LinkConstraintERP; },
512 (s,p,l,v) => { LinkConstraintERP = v; } ),
513 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
514 40,
515 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
516 (s) => { return LinkConstraintSolverIterations; },
517 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
518
519 new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
520 0f,
521 (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); },
522 (s) => { return (float)s.PhysicsMetricDumpFrames; },
523 (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ),
524 new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
525 0f,
526 (s,cf,p,v) => { ; },
527 (s) => { return 0f; },
528 (s,p,l,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
529 new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
530 0f,
531 (s,cf,p,v) => { ; },
532 (s) => { return 0f; },
533 (s,p,l,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
534 };
535
536 // Convert a boolean to our numeric true and false values
537 public static float NumericBool(bool b)
538 {
539 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
540 }
541
542 // Convert numeric true and false values to a boolean
543 public static bool BoolNumeric(float b)
544 {
545 return (b == ConfigurationParameters.numericTrue ? true : false);
546 }
547
548 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
549 {
550 BSScene physScene = pPhysScene;
551 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
552 {
553 physScene.PE.ResetBroadphasePool(physScene.World);
554 });
555 }
556
557 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
558 {
559 BSScene physScene = pPhysScene;
560 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
561 {
562 physScene.PE.ResetConstraintSolver(physScene.World);
563 });
564 }
565
566 // Search through the parameter definitions and return the matching
567 // ParameterDefn structure.
568 // Case does not matter as names are compared after converting to lower case.
569 // Returns 'false' if the parameter is not found.
570 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
571 {
572 bool ret = false;
573 ParameterDefn foundDefn = new ParameterDefn();
574 string pName = paramName.ToLower();
575
576 foreach (ParameterDefn parm in ParameterDefinitions)
577 {
578 if (pName == parm.name.ToLower())
579 {
580 foundDefn = parm;
581 ret = true;
582 break;
583 }
584 }
585 defn = foundDefn;
586 return ret;
587 }
588
589 // Pass through the settable parameters and set the default values
590 internal static void SetParameterDefaultValues(BSScene physicsScene)
591 {
592 foreach (ParameterDefn parm in ParameterDefinitions)
593 {
594 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
595 }
596 }
597
598 // Get user set values out of the ini file.
599 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
600 {
601 foreach (ParameterDefn parm in ParameterDefinitions)
602 {
603 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
604 }
605 }
606
607 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
608
609 // This creates an array in the correct format for returning the list of
610 // parameters. This is used by the 'list' option of the 'physics' command.
611 internal static void BuildParameterTable()
612 {
613 if (SettableParameters.Length < ParameterDefinitions.Length)
614 {
615 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
616 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
617 {
618 ParameterDefn pd = ParameterDefinitions[ii];
619 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
620 }
621
622 // make the list in alphabetical order for estetic reasons
623 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
624 {
625 return ppe1.name.CompareTo(ppe2.name);
626 });
627
628 SettableParameters = entries.ToArray();
629 }
630 }
631
632
633}
634}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..821f470 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time. 46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */ 47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
48public abstract class BSPhysObject : PhysicsActor 58public abstract class BSPhysObject : PhysicsActor
49{ 59{
50 protected BSPhysObject() 60 protected BSPhysObject()
@@ -57,26 +67,45 @@ public abstract class BSPhysObject : PhysicsActor
57 PhysObjectName = name; 67 PhysObjectName = name;
58 TypeName = typeName; 68 TypeName = typeName;
59 69
70 // We don't have any physical representation yet.
71 PhysBody = new BulletBody(localID);
72 PhysShape = new BulletShape();
73
74 // A linkset of just me
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 75 Linkset = BSLinkset.Factory(PhysicsScene, this);
76 PositionDisplacement = OMV.Vector3.Zero;
77
61 LastAssetBuildFailed = false; 78 LastAssetBuildFailed = false;
62 79
80 // Default material type
81 Material = MaterialAttributes.Material.Wood;
82
63 CollisionCollection = new CollisionEventUpdate(); 83 CollisionCollection = new CollisionEventUpdate();
84 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 85 SubscribedEventsMs = 0;
65 CollidingStep = 0; 86 CollidingStep = 0;
66 CollidingGroundStep = 0; 87 CollidingGroundStep = 0;
67 } 88 }
68 89
90 // Tell the object to clean up.
91 public virtual void Destroy()
92 {
93 UnRegisterAllPreStepActions();
94 }
95
69 public BSScene PhysicsScene { get; protected set; } 96 public BSScene PhysicsScene { get; protected set; }
70 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 97 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
71 public string PhysObjectName { get; protected set; } 98 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 99 public string TypeName { get; protected set; }
73 100
74 public BSLinkset Linkset { get; set; } 101 public BSLinkset Linkset { get; set; }
102 public BSLinksetInfo LinksetInfo { get; set; }
75 103
76 // Return the object mass without calculating it or having side effects 104 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 105 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 106 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 107 // 'inWorld' true if the object has already been added to the dynamic world.
108 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 109
81 // The last value calculated for the prim's inertia 110 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 111 public OMV.Vector3 Inertia { get; set; }
@@ -105,9 +134,17 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 134 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 135 public EntityProperties LastEntityProperties { get; set; }
107 136
108 public abstract OMV.Vector3 Scale { get; set; } 137 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 138 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 139 public abstract bool IsStatic { get; }
140 public abstract bool IsSelected { get; }
141
142 // Materialness
143 public MaterialAttributes.Material Material { get; private set; }
144 public override void SetMaterial(int material)
145 {
146 Material = (MaterialAttributes.Material)material;
147 }
111 148
112 // Stop all physical motion. 149 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 150 public abstract void ZeroMotion(bool inTaintTime);
@@ -119,15 +156,41 @@ public abstract class BSPhysObject : PhysicsActor
119 // Update the physical location and motion of the object. Called with data from Bullet. 156 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 157 public abstract void UpdateProperties(EntityProperties entprop);
121 158
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 159 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 160 public abstract OMV.Vector3 ForcePosition { get; set; }
127 161
162 // Position is what the simulator thinks the positions of the prim is.
163 // Because Bullet needs the zero coordinate to be the center of mass of the linkset,
164 // sometimes it is necessary to displace the position the physics engine thinks
165 // the position is. PositionDisplacement must be added and removed from the
166 // position as the simulator position is stored and fetched from the physics
167 // engine.
168 public virtual OMV.Vector3 PositionDisplacement { get; set; }
169
128 public abstract OMV.Quaternion RawOrientation { get; set; } 170 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 171 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 172
173 // The system is telling us the velocity it wants to move at.
174 // Velocity in world coordinates.
175 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
176 public override OMV.Vector3 TargetVelocity
177 {
178 get { return m_targetVelocity; }
179 set
180 {
181 m_targetVelocity = value;
182 Velocity = value;
183 }
184 }
185 public virtual float TargetSpeed
186 {
187 get
188 {
189 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
190 return characterOrientedVelocity.X;
191 }
192 }
193 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 194 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 195
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 196 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +199,15 @@ public abstract class BSPhysObject : PhysicsActor
136 199
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 200 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 201
202 public virtual float ForwardSpeed
203 {
204 get
205 {
206 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
207 return characterOrientedVelocity.X;
208 }
209 }
210
139 #region Collisions 211 #region Collisions
140 212
141 // Requested number of milliseconds between collision events. Zero means disabled. 213 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,26 +218,65 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 218 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 219 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 220 protected long CollidingGroundStep { get; set; }
221 // The simulation step that last collided with an object
222 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 223 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 224 protected CollisionFlags CurrentCollisionFlags { get; set; }
151 225
226 public override bool IsColliding {
227 get { return (CollidingStep == PhysicsScene.SimulationStep); }
228 set {
229 if (value)
230 CollidingStep = PhysicsScene.SimulationStep;
231 else
232 CollidingStep = 0;
233 }
234 }
235 public override bool CollidingGround {
236 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
237 set
238 {
239 if (value)
240 CollidingGroundStep = PhysicsScene.SimulationStep;
241 else
242 CollidingGroundStep = 0;
243 }
244 }
245 public override bool CollidingObj {
246 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
247 set {
248 if (value)
249 CollidingObjectStep = PhysicsScene.SimulationStep;
250 else
251 CollidingObjectStep = 0;
252 }
253 }
254
152 // The collisions that have been collected this tick 255 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 256 protected CollisionEventUpdate CollisionCollection;
257 // Remember collisions from last tick for fancy collision based actions
258 // (like a BSCharacter walking up stairs).
259 protected CollisionEventUpdate CollisionsLastTick;
154 260
155 // The simulation step is telling this object about a collision. 261 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 262 // Return 'true' if a collision was processed and should be sent up.
263 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
157 // Called at taint time from within the Step() function 264 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 265 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 266 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 267 {
161 bool ret = false; 268 bool ret = false;
162 269
163 // The following lines make IsColliding() and IsCollidingGround() work 270 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 271 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 272 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 273 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 274 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 275 }
276 else
277 {
278 CollidingObjectStep = PhysicsScene.SimulationStep;
279 }
169 280
170 // prims in the same linkset cannot collide with each other 281 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) 282 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
@@ -192,7 +303,7 @@ public abstract class BSPhysObject : PhysicsActor
192 { 303 {
193 bool ret = true; 304 bool ret = true;
194 // If the 'no collision' call, force it to happen right now so quick collision_end 305 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 306 bool force = (CollisionCollection.Count == 0);
196 307
197 // throttle the collisions to the number of milliseconds specified in the subscription 308 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 309 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -210,8 +321,13 @@ public abstract class BSPhysObject : PhysicsActor
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 321 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 322 base.SendCollisionUpdate(CollisionCollection);
212 323
213 // The collisionCollection structure is passed around in the simulator. 324 // Remember the collisions from this tick for some collision specific processing.
325 CollisionsLastTick = CollisionCollection;
326
327 // 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. 328 // Make sure we don't have a handle to that one and that a new one is used for next time.
329 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
330 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 331 CollisionCollection = new CollisionEventUpdate();
216 } 332 }
217 return ret; 333 return ret;
@@ -229,7 +345,8 @@ public abstract class BSPhysObject : PhysicsActor
229 345
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 346 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 347 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 348 if (PhysBody.HasPhysicalBody)
349 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 350 });
234 } 351 }
235 else 352 else
@@ -243,7 +360,9 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 360 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 361 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 362 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 363 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
364 if (PhysBody.HasPhysicalBody)
365 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 366 });
248 } 367 }
249 // Return 'true' if the simulator wants collision events 368 // Return 'true' if the simulator wants collision events
@@ -253,11 +372,66 @@ public abstract class BSPhysObject : PhysicsActor
253 372
254 #endregion // Collisions 373 #endregion // Collisions
255 374
375 #region Per Simulation Step actions
376 // There are some actions that must be performed for a physical object before each simulation step.
377 // These actions are optional so, rather than scanning all the physical objects and asking them
378 // if they have anything to do, a physical object registers for an event call before the step is performed.
379 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
380 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
381 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
382 {
383 string identifier = op + "-" + id.ToString();
384
385 lock (RegisteredActions)
386 {
387 // Clean out any existing action
388 UnRegisterPreStepAction(op, id);
389
390 RegisteredActions[identifier] = actn;
391 }
392 PhysicsScene.BeforeStep += actn;
393 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
394 }
395
396 // Unregister a pre step action. Safe to call if the action has not been registered.
397 protected void UnRegisterPreStepAction(string op, uint id)
398 {
399 string identifier = op + "-" + id.ToString();
400 bool removed = false;
401 lock (RegisteredActions)
402 {
403 if (RegisteredActions.ContainsKey(identifier))
404 {
405 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
406 RegisteredActions.Remove(identifier);
407 removed = true;
408 }
409 }
410 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
411 }
412
413 protected void UnRegisterAllPreStepActions()
414 {
415 lock (RegisteredActions)
416 {
417 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
418 {
419 PhysicsScene.BeforeStep -= kvp.Value;
420 }
421 RegisteredActions.Clear();
422 }
423 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
424 }
425
426
427 #endregion // Per Simulation Step actions
428
256 // High performance detailed logging routine used by the physical objects. 429 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 430 protected void DetailLog(string msg, params Object[] args)
258 { 431 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 432 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 433 PhysicsScene.DetailLog(msg, args);
261 } 434 }
435
262} 436}
263} 437}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 20f5180..9442854 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -59,13 +59,7 @@ public class BSPlugin : IPhysicsPlugin
59 { 59 {
60 if (_mScene == null) 60 if (_mScene == null)
61 { 61 {
62 if (Util.IsWindows()) 62 _mScene = new BSScene(GetName(), sceneIdentifier);
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the
65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67
68 _mScene = new BSScene(sceneIdentifier);
69 } 63 }
70 return (_mScene); 64 return (_mScene);
71 } 65 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..79fe632 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,13 +45,15 @@ 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;
52 private bool _isSelected; 51 private bool _isSelected;
53 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53
54 // _position is what the simulator thinks the positions of the prim is.
54 private OMV.Vector3 _position; 55 private OMV.Vector3 _position;
56
55 private float _mass; // the mass of this object 57 private float _mass; // the mass of this object
56 private float _density; 58 private float _density;
57 private OMV.Vector3 _force; 59 private OMV.Vector3 _force;
@@ -67,9 +69,6 @@ public sealed class BSPrim : BSPhysObject
67 private float _restitution; 69 private float _restitution;
68 private bool _setAlwaysRun; 70 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 71 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 72 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 73 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 74 private bool _kinematic;
@@ -77,13 +76,14 @@ public sealed class BSPrim : BSPhysObject
77 76
78 private BSDynamics _vehicle; 77 private BSDynamics _vehicle;
79 78
79 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 80 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 81 private float _PIDTau;
83 private bool _useHoverPID; 82
83 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 84 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 85 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 86 private float _PIDHoverTau;
87 87
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,23 +93,27 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 93 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 94 _position = pos;
95 _size = size; 95 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 96 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 97 _orientation = rotation;
98 _buoyancy = 1f; 98 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 99 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 100 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 101 BaseShape = pbs;
102 _isPhysical = pisPhysical; 102 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 103 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 104
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material 105 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
106 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
107 _density = PhysicsScene.Params.defaultDensity;
108 _friction = PhysicsScene.Params.defaultFriction;
106 _restitution = PhysicsScene.Params.defaultRestitution; 109 _restitution = PhysicsScene.Params.defaultRestitution;
110
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness 111 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
112
108 _mass = CalculateMass(); 113 _mass = CalculateMass();
109 114
110 // No body or shape yet 115 // Cause linkset variables to be initialized (like mass)
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 116 Linkset.Refresh(this);
112 PhysShape = new BulletShape(IntPtr.Zero);
113 117
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 118 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 119 // do the actual object creation at taint time
@@ -117,7 +121,7 @@ public sealed class BSPrim : BSPhysObject
117 { 121 {
118 CreateGeomAndObject(true); 122 CreateGeomAndObject(true);
119 123
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 124 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 125 });
122 } 126 }
123 127
@@ -125,6 +129,7 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 129 public override void Destroy()
126 { 130 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 131 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
132 base.Destroy();
128 133
129 // Undo any links between me and any other object 134 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot; 135 BSPhysObject parentBefore = Linkset.LinksetRoot;
@@ -143,7 +148,9 @@ public sealed class BSPrim : BSPhysObject
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 148 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 149 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 150 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
151 PhysBody.Clear();
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 152 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
153 PhysShape.Clear();
147 }); 154 });
148 } 155 }
149 156
@@ -157,16 +164,15 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 164 // 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. 165 // the physical shape, that is done when the geometry is built.
159 _size = value; 166 _size = value;
167 Scale = _size;
160 ForceBodyShapeRebuild(false); 168 ForceBodyShapeRebuild(false);
161 } 169 }
162 } 170 }
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 171
167 public override PrimitiveBaseShape Shape { 172 public override PrimitiveBaseShape Shape {
168 set { 173 set {
169 BaseShape = value; 174 BaseShape = value;
175 LastAssetBuildFailed = false;
170 ForceBodyShapeRebuild(false); 176 ForceBodyShapeRebuild(false);
171 } 177 }
172 } 178 }
@@ -176,7 +182,6 @@ public sealed class BSPrim : BSPhysObject
176 182
177 public override bool ForceBodyShapeRebuild(bool inTaintTime) 183 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 { 184 {
179 LastAssetBuildFailed = false;
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() 185 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 { 186 {
182 _mass = CalculateMass(); // changing the shape changes the mass 187 _mass = CalculateMass(); // changing the shape changes the mass
@@ -189,15 +194,23 @@ public sealed class BSPrim : BSPhysObject
189 } 194 }
190 } 195 }
191 public override bool Selected { 196 public override bool Selected {
192 set { 197 set
193 _isSelected = value; 198 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 199 if (value != _isSelected)
195 { 200 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 201 _isSelected = value;
197 SetObjectDynamic(false); 202 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 203 {
204 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
205 SetObjectDynamic(false);
206 });
207 }
199 } 208 }
200 } 209 }
210 public override bool IsSelected
211 {
212 get { return _isSelected; }
213 }
201 public override void CrossingFailure() { return; } 214 public override void CrossingFailure() { return; }
202 215
203 // link me to the specified parent 216 // link me to the specified parent
@@ -244,7 +257,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 257 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 258 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 259 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 260 if (PhysBody.HasPhysicalBody)
261 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 262 });
249 } 263 }
250 public override void ZeroAngularMotion(bool inTaintTime) 264 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,8 +267,12 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 267 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 268 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 269 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 270 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 271 if (PhysBody.HasPhysicalBody)
272 {
273 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
274 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
275 }
258 }); 276 });
259 } 277 }
260 278
@@ -271,41 +289,69 @@ public sealed class BSPrim : BSPhysObject
271 } 289 }
272 public override OMV.Vector3 Position { 290 public override OMV.Vector3 Position {
273 get { 291 get {
292 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
293 * 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 294 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this)) 295 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this); 296 _position = Linkset.PositionGet(this);
297 */
277 298
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 299 // 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); 300 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody) - PositionDisplacement;
280 return _position; 301 return _position;
281 } 302 }
282 set { 303 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 304 // If the position must be forced into the physics engine, use ForcePosition.
305 // All positions are given in world positions.
284 if (_position == value) 306 if (_position == value)
285 { 307 {
308 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 309 return;
287 } 310 }
288 _position = value; 311 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 312 PositionSanityCheck(false);
313
314 // A linkset might need to know if a component information changed.
315 Linkset.UpdateProperties(this, false);
316
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 317 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 318 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 319 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 320 ForcePosition = _position;
295 ActivateIfPhysical(false);
296 }); 321 });
297 } 322 }
298 } 323 }
299 public override OMV.Vector3 ForcePosition { 324 public override OMV.Vector3 ForcePosition {
300 get { 325 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 326 _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement;
302 return _position; 327 return _position;
303 } 328 }
304 set { 329 set {
305 _position = value; 330 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 331 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 332 {
308 ActivateIfPhysical(false); 333 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
334 ActivateIfPhysical(false);
335 }
336 }
337 }
338 // Override to have position displacement immediately update the physical position.
339 // A feeble attempt to keep the sim and physical positions in sync
340 // Must be called at taint time.
341 public override OMV.Vector3 PositionDisplacement
342 {
343 get
344 {
345 return base.PositionDisplacement;
346 }
347 set
348 {
349 base.PositionDisplacement = value;
350 PhysicsScene.TaintedObject(PhysicsScene.InTaintTime, "BSPrim.setPosition", delegate()
351 {
352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.SetTranslation(PhysBody, _position + base.PositionDisplacement, _orientation);
354 });
309 } 355 }
310 } 356 }
311 357
@@ -316,51 +362,56 @@ public sealed class BSPrim : BSPhysObject
316 { 362 {
317 bool ret = false; 363 bool ret = false;
318 364
365 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
366 {
367 // The physical object is out of the known/simulated area.
368 // Upper levels of code will handle the transition to other areas so, for
369 // the time, we just ignore the position.
370 return ret;
371 }
372
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 373 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 374 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 375 if (RawPosition.Z < terrainHeight)
322 { 376 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 377 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 378 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 379 // If the object is below ground it just has to be moved up because pushing will
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 380 // not get it through the terrain
381 _position.Z = targetHeight;
382 if (inTaintTime)
383 ForcePosition = _position;
327 ret = true; 384 ret = true;
328 } 385 }
329 386
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 387 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 388 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 389 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 390 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 391 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 392 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 393 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 394 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
395
396 // Apply upforce and overcome gravity.
397 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
398 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
399 AddForce(correctionForce, false, inTaintTime);
338 ret = true; 400 ret = true;
339 } 401 }
340 } 402 }
341 403
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.
345 if (ret)
346 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
348 {
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 }
353 return ret; 404 return ret;
354 } 405 }
355 406
356 // Return the effective mass of the object. 407 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 408 // The definition of this call is to return the mass of the prim.
409 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 410 public override float Mass
359 { 411 {
360 get 412 get
361 { 413 {
362 return Linkset.LinksetMass; 414 return _mass;
363 // return _mass;
364 } 415 }
365 } 416 }
366 417
@@ -370,25 +421,64 @@ public sealed class BSPrim : BSPhysObject
370 } 421 }
371 // Set the physical mass to the passed mass. 422 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 423 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 424 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 425 {
375 if (IsStatic) 426 if (PhysBody.HasPhysicalBody)
376 {
377 Inertia = OMV.Vector3.Zero;
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
380 }
381 else
382 { 427 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 428 if (IsStatic)
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 429 {
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 430 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
386 // center of mass is at the zero of the object 431 Inertia = OMV.Vector3.Zero;
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); 432 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); 433 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
434 }
435 else
436 {
437 OMV.Vector3 grav = ComputeGravity(Buoyancy);
438
439 if (inWorld)
440 {
441 // Changing interesting properties doesn't change proxy and collision cache
442 // information. The Bullet solution is to re-add the object to the world
443 // after parameters are changed.
444 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
445 }
446
447 // The computation of mass props requires gravity to be set on the object.
448 PhysicsScene.PE.SetGravity(PhysBody, grav);
449
450 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
451 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
452 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
453
454 // center of mass is at the zero of the object
455 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
456 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
457
458 if (inWorld)
459 {
460 AddObjectToPhysicalWorld();
461 }
462
463 // Must set gravity after it has been added to the world because, for unknown reasons,
464 // adding the object resets the object's gravity to world gravity
465 PhysicsScene.PE.SetGravity(PhysBody, grav);
466
467 }
389 } 468 }
390 } 469 }
391 470
471 // Return what gravity should be set to this very moment
472 public OMV.Vector3 ComputeGravity(float buoyancy)
473 {
474 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
475
476 if (!IsStatic)
477 ret *= (1f - buoyancy);
478
479 return ret;
480 }
481
392 // Is this used? 482 // Is this used?
393 public override OMV.Vector3 CenterOfMass 483 public override OMV.Vector3 CenterOfMass
394 { 484 {
@@ -405,11 +495,26 @@ public sealed class BSPrim : BSPhysObject
405 get { return _force; } 495 get { return _force; }
406 set { 496 set {
407 _force = value; 497 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 498 if (_force != OMV.Vector3.Zero)
409 { 499 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 500 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 501 // Bullet clears the forces applied last frame.
412 }); 502 RegisterPreStepAction("BSPrim.setForce", LocalID,
503 delegate(float timeStep)
504 {
505 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
506 if (PhysBody.HasPhysicalBody)
507 {
508 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
509 ActivateIfPhysical(false);
510 }
511 }
512 );
513 }
514 else
515 {
516 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
517 }
413 } 518 }
414 } 519 }
415 520
@@ -420,15 +525,18 @@ public sealed class BSPrim : BSPhysObject
420 set { 525 set {
421 Vehicle type = (Vehicle)value; 526 Vehicle type = (Vehicle)value;
422 527
423 // Tell the scene about the vehicle so it will get processing each frame.
424 PhysicsScene.VehicleInSceneTypeChanged(this, type);
425
426 PhysicsScene.TaintedObject("setVehicleType", delegate() 528 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 529 {
428 // Done at taint time so we're sure the physics engine is not using the variables 530 // Done at taint time so we're sure the physics engine is not using the variables
429 // Vehicle code changes the parameters for this vehicle type. 531 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 532 _vehicle.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 533 ActivateIfPhysical(false);
534
535 // If an active vehicle, register the vehicle code to be called before each step
536 if (_vehicle.Type == Vehicle.TYPE_NONE)
537 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
538 else
539 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
432 }); 540 });
433 } 541 }
434 } 542 }
@@ -464,23 +572,6 @@ public sealed class BSPrim : BSPhysObject
464 }); 572 });
465 } 573 }
466 574
467 // Called each simulation step to advance vehicle characteristics.
468 // Called from Scene when doing simulation step so we're in taint processing time.
469 public override void StepVehicle(float timeStep)
470 {
471 if (IsPhysical && _vehicle.IsActive)
472 {
473 _vehicle.Step(timeStep);
474 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
475 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
476 {
477 // This resets the interpolation values and recomputes the tensor variables
478 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
479 });
480 */
481 }
482 }
483
484 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 575 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 576 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 577 bool newValue = (param != 0);
@@ -495,6 +586,11 @@ public sealed class BSPrim : BSPhysObject
495 } 586 }
496 return; 587 return;
497 } 588 }
589 public override OMV.Vector3 RawVelocity
590 {
591 get { return _velocity; }
592 set { _velocity = value; }
593 }
498 public override OMV.Vector3 Velocity { 594 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 595 get { return _velocity; }
500 set { 596 set {
@@ -502,22 +598,44 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 598 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 599 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 600 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 601 ForceVelocity = _velocity;
506 }); 602 });
507 } 603 }
508 } 604 }
509 public override OMV.Vector3 ForceVelocity { 605 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 606 get { return _velocity; }
511 set { 607 set {
608 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
609
512 _velocity = value; 610 _velocity = value;
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 611 if (PhysBody.HasPhysicalBody)
612 {
613 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
614 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
615 ActivateIfPhysical(false);
616 }
514 } 617 }
515 } 618 }
516 public override OMV.Vector3 Torque { 619 public override OMV.Vector3 Torque {
517 get { return _torque; } 620 get { return _torque; }
518 set { 621 set {
519 _torque = value; 622 _torque = value;
520 AddAngularForce(_torque, false, false); 623 if (_torque != OMV.Vector3.Zero)
624 {
625 // If the torque is non-zero, it must be reapplied each tick because
626 // Bullet clears the forces applied last frame.
627 RegisterPreStepAction("BSPrim.setTorque", LocalID,
628 delegate(float timeStep)
629 {
630 if (PhysBody.HasPhysicalBody)
631 AddAngularForce(_torque, false, true);
632 }
633 );
634 }
635 else
636 {
637 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
638 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 639 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 640 }
523 } 641 }
@@ -537,23 +655,27 @@ public sealed class BSPrim : BSPhysObject
537 } 655 }
538 public override OMV.Quaternion Orientation { 656 public override OMV.Quaternion Orientation {
539 get { 657 get {
658 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
659 * 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. 660 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this)) 661 if (!Linkset.IsRoot(this))
542 { 662 {
543 _orientation = Linkset.Orientation(this); 663 _orientation = Linkset.OrientationGet(this);
544 } 664 }
665 */
545 return _orientation; 666 return _orientation;
546 } 667 }
547 set { 668 set {
548 if (_orientation == value) 669 if (_orientation == value)
549 return; 670 return;
550 _orientation = value; 671 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 672
673 // A linkset might need to know if a component information changed.
674 Linkset.UpdateProperties(this, false);
675
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 676 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 677 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 678 ForceOrientation = _orientation;
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
557 }); 679 });
558 } 680 }
559 } 681 }
@@ -562,13 +684,14 @@ public sealed class BSPrim : BSPhysObject
562 { 684 {
563 get 685 get
564 { 686 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 687 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 688 return _orientation;
567 } 689 }
568 set 690 set
569 { 691 {
570 _orientation = value; 692 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 693 if (PhysBody.HasPhysicalBody)
694 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
572 } 695 }
573 } 696 }
574 public override int PhysicsActorType { 697 public override int PhysicsActorType {
@@ -583,7 +706,7 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 706 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 707 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 708 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 709 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 710 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 711 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 712 ZeroMotion(true);
@@ -624,7 +747,7 @@ public sealed class BSPrim : BSPhysObject
624 747
625 // Mangling all the physical properties requires the object not be in the physical world. 748 // Mangling all the physical properties requires the object not be in the physical world.
626 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 749 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
627 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 750 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 751
629 // Set up the object physicalness (does gravity and collisions move this object) 752 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 753 MakeDynamic(IsStatic);
@@ -638,16 +761,10 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 761 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 762 MakeSolid(IsSolid);
640 763
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 764 AddObjectToPhysicalWorld();
642 765
643 // Rebuild its shape 766 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 767 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
645
646 // Collision filter can be set only when the object is in the world
647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
648 {
649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
650 }
651 768
652 // Recompute any linkset parameters. 769 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that 770 // When going from non-physical to physical, this re-enables the constraints that
@@ -655,8 +772,8 @@ public sealed class BSPrim : BSPhysObject
655 // For compound based linksets, this enables and disables interactions of the children. 772 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this); 773 Linkset.Refresh(this);
657 774
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 775 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
659 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); 776 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 777 }
661 778
662 // "Making dynamic" means changing to and from static. 779 // "Making dynamic" means changing to and from static.
@@ -669,74 +786,80 @@ public sealed class BSPrim : BSPhysObject
669 if (makeStatic) 786 if (makeStatic)
670 { 787 {
671 // Become a Bullet 'static' object type 788 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 789 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 790 // Stop all movement
674 ZeroMotion(true); 791 ZeroMotion(true);
675 // Center of mass is at the center of the object 792
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 793 // Set various physical properties so other object interact properly
794 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
795 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
796 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
797
677 // Mass is zero which disables a bunch of physics stuff in Bullet 798 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 799 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 800 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 801 if (BSParam.CcdMotionThreshold > 0f)
681 { 802 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 803 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 804 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 805 }
685 // There can be special things needed for implementing linksets 806
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 807 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 808 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 809 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 810 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
811
812 // This collides like a static object
813 PhysBody.collisionType = CollisionType.Static;
691 814
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 815 // There can be special things needed for implementing linksets
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 816 Linkset.MakeStatic(this);
694 } 817 }
695 else 818 else
696 { 819 {
697 // Not a Bullet static object 820 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 821 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 822
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 823 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 824 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 825 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
826 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
703 827
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 828 // 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 829 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 830 // PhysicsScene.PE.ClearAllForces(BSBody);
707 831
708 // For good measure, make sure the transform is set through to the motion state 832 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 833 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
710 834
711 // Center of mass is at the center of the object 835 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 836 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
713 837
714 // A dynamic object has mass 838 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 839 UpdatePhysicalMassProperties(RawMass, false);
716 840
717 // Set collision detection parameters 841 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 842 if (BSParam.CcdMotionThreshold > 0f)
719 { 843 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 844 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 845 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 846 }
723 847
724 // Various values for simulation limits 848 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 849 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 850 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 851 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 852 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 853
730 // There might be special things needed for implementing linksets. 854 // This collides like an object.
731 Linkset.MakeDynamic(this); 855 PhysBody.collisionType = CollisionType.Dynamic;
732 856
733 // Force activation of the object so Bullet will act on it. 857 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 858 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 859 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737 860
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 861 // There might be special things needed for implementing linksets.
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 862 Linkset.MakeDynamic(this);
740 } 863 }
741 } 864 }
742 865
@@ -746,7 +869,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 869 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 870 private void MakeSolid(bool makeSolid)
748 { 871 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 872 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 873 if (makeSolid)
751 { 874 {
752 // Verify the previous code created the correct shape for this type of thing. 875 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +877,7 @@ public sealed class BSPrim : BSPhysObject
754 { 877 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 878 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 879 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 880 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 881 }
759 else 882 else
760 { 883 {
@@ -762,9 +885,10 @@ public sealed class BSPrim : BSPhysObject
762 { 885 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 886 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 887 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 888 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 889
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 890 // Change collision info from a static object to a ghosty collision object
891 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 892 }
769 } 893 }
770 894
@@ -773,8 +897,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 897 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 898 private void ActivateIfPhysical(bool forceIt)
775 { 899 {
776 if (IsPhysical) 900 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 901 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 902 }
779 903
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 904 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +906,27 @@ public sealed class BSPrim : BSPhysObject
782 { 906 {
783 if (wantsCollisionEvents) 907 if (wantsCollisionEvents)
784 { 908 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 909 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
910 }
911 else
912 {
913 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
914 }
915 }
916
917 // Add me to the physical world.
918 // Object MUST NOT already be in the world.
919 // This routine exists because some assorted properties get mangled by adding to the world.
920 internal void AddObjectToPhysicalWorld()
921 {
922 if (PhysBody.HasPhysicalBody)
923 {
924 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
786 } 925 }
787 else 926 else
788 { 927 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 928 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
929 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 930 }
791 } 931 }
792 932
@@ -805,18 +945,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 945 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 946 set { _throttleUpdates = value; }
807 } 947 }
808 public override bool IsColliding {
809 get { return (CollidingStep == PhysicsScene.SimulationStep); }
810 set { _isColliding = value; }
811 }
812 public override bool CollidingGround {
813 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
814 set { _collidingGround = value; }
815 }
816 public override bool CollidingObj {
817 get { return _collidingObj; }
818 set { _collidingObj = value; }
819 }
820 public bool IsPhantom { 948 public bool IsPhantom {
821 get { 949 get {
822 // SceneObjectPart removes phantom objects from the physics scene 950 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,23 +959,14 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 959 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 960 {
833 if (_floatOnWater) 961 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 962 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 963 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 964 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 965 });
838 } 966 }
839 } 967 }
840 public override OMV.Vector3 RotationalVelocity { 968 public override OMV.Vector3 RotationalVelocity {
841 get { 969 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; 970 return _rotationalVelocity;
852 } 971 }
853 set { 972 set {
@@ -856,7 +975,7 @@ public sealed class BSPrim : BSPhysObject
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 975 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 976 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 977 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 978 ForceRotationalVelocity = _rotationalVelocity;
860 }); 979 });
861 } 980 }
862 } 981 }
@@ -866,7 +985,11 @@ public sealed class BSPrim : BSPhysObject
866 } 985 }
867 set { 986 set {
868 _rotationalVelocity = value; 987 _rotationalVelocity = value;
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 988 if (PhysBody.HasPhysicalBody)
989 {
990 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
991 ActivateIfPhysical(false);
992 }
870 } 993 }
871 } 994 }
872 public override bool Kinematic { 995 public override bool Kinematic {
@@ -890,9 +1013,10 @@ public sealed class BSPrim : BSPhysObject
890 set { 1013 set {
891 _buoyancy = value; 1014 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1015 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 1016 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 1017 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 1018 UpdatePhysicalMassProperties(_mass, true);
1019 ActivateIfPhysical(false);
896 } 1020 }
897 } 1021 }
898 1022
@@ -900,17 +1024,103 @@ public sealed class BSPrim : BSPhysObject
900 public override OMV.Vector3 PIDTarget { 1024 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1025 set { _PIDTarget = value; }
902 } 1026 }
903 public override bool PIDActive {
904 set { _usePID = value; }
905 }
906 public override float PIDTau { 1027 public override float PIDTau {
907 set { _PIDTau = value; } 1028 set { _PIDTau = value; }
908 } 1029 }
1030 public override bool PIDActive {
1031 set {
1032 if (value)
1033 {
1034 // We're taking over after this.
1035 ZeroMotion(true);
1036
1037 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1038 _PIDTau, // timeScale
1039 BSMotor.Infinite, // decay time scale
1040 BSMotor.InfiniteVector, // friction timescale
1041 1f // efficiency
1042 );
1043 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1044 _targetMotor.SetTarget(_PIDTarget);
1045 _targetMotor.SetCurrent(RawPosition);
1046 /*
1047 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1048 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1049
1050 _targetMotor.SetTarget(_PIDTarget);
1051 _targetMotor.SetCurrent(RawPosition);
1052 _targetMotor.TimeScale = _PIDTau;
1053 _targetMotor.Efficiency = 1f;
1054 */
1055
1056 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1057 {
1058 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1059
1060 // 'movePosition' is where we'd like the prim to be at this moment.
1061 OMV.Vector3 movePosition = _targetMotor.Step(timeStep);
1062
1063 // If we are very close to our target, turn off the movement motor.
1064 if (_targetMotor.ErrorIsZero())
1065 {
1066 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1067 LocalID, movePosition, RawPosition, Mass);
1068 ForcePosition = _targetMotor.TargetValue;
1069 _targetMotor.Enabled = false;
1070 }
1071 else
1072 {
1073 ForcePosition = movePosition;
1074 }
1075 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1076 });
1077 }
1078 else
1079 {
1080 // Stop any targetting
1081 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1082 }
1083 }
1084 }
909 1085
910 // Used for llSetHoverHeight and maybe vehicle height 1086 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1087 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1088 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1089 set {
1090 if (value)
1091 {
1092 // Turning the target on
1093 _hoverMotor = new BSFMotor("BSPrim.Hover",
1094 _PIDHoverTau, // timeScale
1095 BSMotor.Infinite, // decay time scale
1096 BSMotor.Infinite, // friction timescale
1097 1f // efficiency
1098 );
1099 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1100 _hoverMotor.SetCurrent(RawPosition.Z);
1101 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1102
1103 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1104 {
1105 _hoverMotor.SetCurrent(RawPosition.Z);
1106 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1107 float targetHeight = _hoverMotor.Step(timeStep);
1108
1109 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1110 // Compute the amount of force to push us there.
1111 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1112 // Undo anything the object thinks it's doing at the moment
1113 moveForce = -RawVelocity.Z * Mass;
1114
1115 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1116 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1117 });
1118 }
1119 else
1120 {
1121 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1122 }
1123 }
914 } 1124 }
915 public override float PIDHoverHeight { 1125 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1126 set { _PIDHoverHeight = value; }
@@ -919,8 +1129,35 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1129 set { _PIDHoverType = value; }
920 } 1130 }
921 public override float PIDHoverTau { 1131 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1132 set { _PIDHoverTau = value; }
923 } 1133 }
1134 // Based on current position, determine what we should be hovering at now.
1135 // Must recompute often. What if we walked offa cliff>
1136 private float ComputeCurrentPIDHoverHeight()
1137 {
1138 float ret = _PIDHoverHeight;
1139 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1140
1141 switch (_PIDHoverType)
1142 {
1143 case PIDHoverType.Ground:
1144 ret = groundHeight + _PIDHoverHeight;
1145 break;
1146 case PIDHoverType.GroundAndWater:
1147 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1148 if (groundHeight > waterHeight)
1149 {
1150 ret = groundHeight + _PIDHoverHeight;
1151 }
1152 else
1153 {
1154 ret = waterHeight + _PIDHoverHeight;
1155 }
1156 break;
1157 }
1158 return ret;
1159 }
1160
924 1161
925 // For RotLookAt 1162 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1163 public override OMV.Quaternion APIDTarget { set { return; } }
@@ -928,54 +1165,82 @@ public sealed class BSPrim : BSPhysObject
928 public override float APIDStrength { set { return; } } 1165 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1166 public override float APIDDamping { set { return; } }
930 1167
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1168 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1169 // Since this force is being applied in only one step, make this a force per second.
1170 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1171 AddForce(addForce, pushforce, false);
934 } 1172 }
935 // Applying a force just adds this to the total force on the object. 1173 // Applying a force just adds this to the total force on the object.
1174 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1175 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1176 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1177 if (!IsStatic)
939 { 1178 {
940 // _force += force; 1179 if (force.IsFinite())
941 lock (m_accumulatedForces)
942 m_accumulatedForces.Add(new OMV.Vector3(force));
943 }
944 else
945 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
947 return;
948 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero;
952 lock (m_accumulatedForces)
953 { 1180 {
954 // Sum the accumulated additional forces for one big force to apply once. 1181 float magnitude = force.Length();
955 foreach (OMV.Vector3 v in m_accumulatedForces) 1182 if (magnitude > BSParam.MaxAddForceMagnitude)
956 { 1183 {
957 fSum += v; 1184 // Force has a limit
1185 force = force / magnitude * BSParam.MaxAddForceMagnitude;
958 } 1186 }
959 m_accumulatedForces.Clear(); 1187
1188 OMV.Vector3 addForce = force;
1189 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1190
1191 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1192 {
1193 // Bullet adds this central force to the total force for this tick
1194 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1195 if (PhysBody.HasPhysicalBody)
1196 {
1197 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1198 ActivateIfPhysical(false);
1199 }
1200 });
960 } 1201 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 1202 else
962 if (fSum != OMV.Vector3.Zero) 1203 {
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 1204 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
964 }); 1205 return;
1206 }
1207 }
965 } 1208 }
966 1209
967 // An impulse force is scaled by the mass of the object. 1210 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 1211 // for an object, doesn't matter if force is a pushforce or not
969 { 1212 if (!IsStatic)
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1213 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1214 if (impulse.IsFinite())
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1215 {
975 }); 1216 float magnitude = impulse.Length();
1217 if (magnitude > BSParam.MaxAddForceMagnitude)
1218 {
1219 // Force has a limit
1220 impulse = impulse / magnitude * BSParam.MaxAddForceMagnitude;
1221 }
1222
1223 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1224 OMV.Vector3 addImpulse = impulse;
1225 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1226 {
1227 // Bullet adds this impulse immediately to the velocity
1228 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1229 if (PhysBody.HasPhysicalBody)
1230 {
1231 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1232 ActivateIfPhysical(false);
1233 }
1234 });
1235 }
1236 else
1237 {
1238 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1239 return;
1240 }
1241 }
976 } 1242 }
977 1243
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1244 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1245 AddAngularForce(force, pushforce, false);
981 } 1246 }
@@ -983,42 +1248,37 @@ public sealed class BSPrim : BSPhysObject
983 { 1248 {
984 if (force.IsFinite()) 1249 if (force.IsFinite())
985 { 1250 {
986 // _force += force; 1251 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1252 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1253 {
1254 if (PhysBody.HasPhysicalBody)
1255 {
1256 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1257 ActivateIfPhysical(false);
1258 }
1259 });
989 } 1260 }
990 else 1261 else
991 { 1262 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1263 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1264 return;
994 } 1265 }
995 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
996 {
997 OMV.Vector3 fSum = OMV.Vector3.Zero;
998 lock (m_accumulatedAngularForces)
999 {
1000 // Sum the accumulated additional forces for one big force to apply once.
1001 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
1002 {
1003 fSum += v;
1004 }
1005 m_accumulatedAngularForces.Clear();
1006 }
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero)
1009 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum;
1012 }
1013 });
1014 } 1266 }
1267
1015 // A torque impulse. 1268 // A torque impulse.
1269 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1270 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1271 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1272 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1273 {
1018 OMV.Vector3 applyImpulse = impulse; 1274 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1275 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1276 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1277 if (PhysBody.HasPhysicalBody)
1278 {
1279 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1280 ActivateIfPhysical(false);
1281 }
1022 }); 1282 });
1023 } 1283 }
1024 1284
@@ -1313,11 +1573,7 @@ public sealed class BSPrim : BSPhysObject
1313 } 1573 }
1314 */ 1574 */
1315 1575
1316 if (returnMass <= 0) 1576 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1317 returnMass = 0.0001f;
1318
1319 if (returnMass > PhysicsScene.MaximumObjectMass)
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1577
1322 return returnMass; 1578 return returnMass;
1323 }// end CalculateMass 1579 }// end CalculateMass
@@ -1326,7 +1582,7 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1582 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1583 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1584 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1585 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1586 {
1331 // If this prim is part of a linkset, we must remove and restore the physical 1587 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt. 1588 // links if the body is rebuilt.
@@ -1336,12 +1592,11 @@ public sealed class BSPrim : BSPhysObject
1336 // Create the correct physical representation for this type of object. 1592 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1593 // Updates PhysBody and PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1594 // 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) 1595 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1596 {
1342 // Called if the current prim body is about to be destroyed. 1597 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1598 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1599 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1600 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1601 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 }); 1602 });
@@ -1364,72 +1619,20 @@ public sealed class BSPrim : BSPhysObject
1364 1619
1365 // The physics engine says that properties have updated. Update same and inform 1620 // The physics engine says that properties have updated. Update same and inform
1366 // the world that things have changed. 1621 // the world that things have changed.
1367 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1368 enum UpdatedProperties {
1369 Position = 1 << 0,
1370 Rotation = 1 << 1,
1371 Velocity = 1 << 2,
1372 Acceleration = 1 << 3,
1373 RotationalVel = 1 << 4
1374 }
1375
1376 const float ROTATION_TOLERANCE = 0.01f;
1377 const float VELOCITY_TOLERANCE = 0.001f;
1378 const float POSITION_TOLERANCE = 0.05f;
1379 const float ACCELERATION_TOLERANCE = 0.01f;
1380 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1381
1382 public override void UpdateProperties(EntityProperties entprop) 1622 public override void UpdateProperties(EntityProperties entprop)
1383 { 1623 {
1384 /* 1624 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1625 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 { 1626 {
1419 // Only update the position of single objects and linkset roots 1627 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1628 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1629 if (_vehicle.IsActive)
1421 { 1630 {
1422 base.RequestPhysicsterseUpdate(); 1631 entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1632 }
1424 }
1425 */
1426
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1428 1633
1429 // Updates only for individual prims and for the root object of a linkset. 1634 // Assign directly to the local variables so the normal set actions do not happen
1430 if (Linkset.IsRoot(this)) 1635 entprop.Position -= PositionDisplacement;
1431 {
1432 // Assign directly to the local variables so the normal set action does not happen
1433 _position = entprop.Position; 1636 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1637 _orientation = entprop.Rotation;
1435 _velocity = entprop.Velocity; 1638 _velocity = entprop.Velocity;
@@ -1437,21 +1640,19 @@ public sealed class BSPrim : BSPhysObject
1437 _rotationalVelocity = entprop.RotationalVelocity; 1640 _rotationalVelocity = entprop.RotationalVelocity;
1438 1641
1439 // The sanity check can change the velocity and/or position. 1642 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true)) 1643 if (IsPhysical && PositionSanityCheck(true))
1441 { 1644 {
1442 entprop.Position = _position; 1645 entprop.Position = _position;
1443 entprop.Velocity = _velocity; 1646 entprop.Velocity = _velocity;
1444 } 1647 }
1445 1648
1446 // remember the current and last set values 1649 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}", 1650 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); 1651 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453 1652
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1653 // remember the current and last set values
1654 LastEntityProperties = CurrentEntityProperties;
1655 CurrentEntityProperties = entprop;
1455 1656
1456 base.RequestPhysicsterseUpdate(); 1657 base.RequestPhysicsterseUpdate();
1457 } 1658 }
@@ -1466,7 +1667,7 @@ public sealed class BSPrim : BSPhysObject
1466 */ 1667 */
1467 1668
1468 // The linkset implimentation might want to know about this. 1669 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this); 1670 Linkset.UpdateProperties(this, true);
1470 } 1671 }
1471} 1672}
1472} 1673}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..e0b4992 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Runtime.InteropServices; 30using System.Runtime.InteropServices;
30using System.Text; 31using System.Text;
31using System.Threading; 32using System.Threading;
@@ -38,40 +39,22 @@ using Nini.Config;
38using log4net; 39using log4net;
39using OpenMetaverse; 40using OpenMetaverse;
40 41
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
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
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
56// 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?
60// Check terrain size. 128 or 127?
61// Raycast
62//
63namespace OpenSim.Region.Physics.BulletSPlugin 42namespace OpenSim.Region.Physics.BulletSPlugin
64{ 43{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 44public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 45{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 46 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 47 internal static readonly string LogHeader = "[BULLETS SCENE]";
69 48
70 // The name of the region we're working for. 49 // The name of the region we're working for.
71 public string RegionName { get; private set; } 50 public string RegionName { get; private set; }
72 51
73 public string BulletSimVersion = "?"; 52 public string BulletSimVersion = "?";
74 53
54 // The handle to the underlying managed or unmanaged version of Bullet being used.
55 public string BulletEngineName { get; private set; }
56 public BSAPITemplate PE;
57
75 public Dictionary<uint, BSPhysObject> PhysObjects; 58 public Dictionary<uint, BSPhysObject> PhysObjects;
76 public BSShapeCollection Shapes; 59 public BSShapeCollection Shapes;
77 60
@@ -82,32 +65,30 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
82 // every tick so OpenSim will update its animation. 65 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 66 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
84 67
85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
88
89 // let my minuions use my logger 68 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } } 69 public ILog Logger { get { return m_log; } }
91 70
92 public IMesher mesher; 71 public IMesher mesher;
93 // Level of Detail values kept as float because that's what the Meshmerizer wants
94 public float MeshLOD { get; private set; }
95 public float MeshMegaPrimLOD { get; private set; }
96 public float MeshMegaPrimThreshold { get; private set; }
97 public float SculptLOD { get; private set; }
98
99 public uint WorldID { get; private set; } 72 public uint WorldID { get; private set; }
100 public BulletSim World { get; private set; } 73 public BulletWorld World { get; private set; }
101 74
102 // All the constraints that have been allocated in this instance. 75 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; } 76 public BSConstraintCollection Constraints { get; private set; }
104 77
105 // Simulation parameters 78 // Simulation parameters
106 private int m_maxSubSteps; 79 internal int m_maxSubSteps;
107 private float m_fixedTimeStep; 80 internal float m_fixedTimeStep;
108 private long m_simulationStep = 0; 81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; }
109 public long SimulationStep { get { return m_simulationStep; } } 83 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep; 84 internal int m_taintsToProcessPerStep;
85 internal float LastTimeStep { get; private set; }
86
87 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep);
89 public delegate void PostStepAction(float timeStep);
90 public event PreStepAction BeforeStep;
91 public event PreStepAction AfterStep;
111 92
112 // A value of the time now so all the collision and update routines do not have to get their own 93 // 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 94 // Set to 'now' just before all the prims and actors are called for collisions and updates
@@ -121,31 +102,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
121 public bool InTaintTime { get; private set; } 102 public bool InTaintTime { get; private set; }
122 103
123 // Pinned memory used to pass step information between managed and unmanaged 104 // Pinned memory used to pass step information between managed and unmanaged
124 private int m_maxCollisionsPerFrame; 105 internal int m_maxCollisionsPerFrame;
125 private CollisionDesc[] m_collisionArray; 106 internal CollisionDesc[] m_collisionArray;
126 private GCHandle m_collisionArrayPinnedHandle;
127 107
128 private int m_maxUpdatesPerFrame; 108 internal int m_maxUpdatesPerFrame;
129 private EntityProperties[] m_updateArray; 109 internal EntityProperties[] m_updateArray;
130 private GCHandle m_updateArrayPinnedHandle;
131
132 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
134 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
135
136 public float PID_D { get; private set; } // derivative
137 public float PID_P { get; private set; } // proportional
138 110
139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 111 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
140 public const uint GROUNDPLANE_ID = 1; 112 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 113 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142 114
143 private float m_waterLevel; 115 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; } 116 public BSTerrainManager TerrainManager { get; private set; }
145 117
146 public ConfigurationParameters Params 118 public ConfigurationParameters Params
147 { 119 {
148 get { return m_params[0]; } 120 get { return UnmanagedParams[0]; }
149 } 121 }
150 public Vector3 DefaultGravity 122 public Vector3 DefaultGravity
151 { 123 {
@@ -157,8 +129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
157 get { return Params.gravity; } 129 get { return Params.gravity; }
158 } 130 }
159 131
160 public float MaximumObjectMass { get; private set; }
161
162 // When functions in the unmanaged code must be called, it is only 132 // When functions in the unmanaged code must be called, it is only
163 // done at a known time just before the simulation step. The taint 133 // done at a known time just before the simulation step. The taint
164 // system saves all these function calls and executes them in 134 // system saves all these function calls and executes them in
@@ -181,13 +151,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
181 151
182 // A pointer to an instance if this structure is passed to the C++ code 152 // A pointer to an instance if this structure is passed to the C++ code
183 // Used to pass basic configuration values to the unmanaged code. 153 // Used to pass basic configuration values to the unmanaged code.
184 ConfigurationParameters[] m_params; 154 internal ConfigurationParameters[] UnmanagedParams;
185 GCHandle m_paramsHandle;
186
187 // Handle to the callback used by the unmanaged code to call into the managed code.
188 // Used for debug logging.
189 // Need to store the handle in a persistant variable so it won't be freed.
190 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
191 155
192 // Sometimes you just have to log everything. 156 // Sometimes you just have to log everything.
193 public Logging.LogWriter PhysicsLogging; 157 public Logging.LogWriter PhysicsLogging;
@@ -195,15 +159,24 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
195 private string m_physicsLoggingDir; 159 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix; 160 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes; 161 private int m_physicsLoggingFileMinutes;
162 private bool m_physicsLoggingDoFlush;
163 private bool m_physicsPhysicalDumpEnabled;
164 public float PhysicsMetricDumpFrames { get; set; }
198 // 'true' of the vehicle code is to log lots of details 165 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; } 166 public bool VehicleLoggingEnabled { get; private set; }
167 public bool VehiclePhysicalLoggingEnabled { get; private set; }
200 168
201 #region Construction and Initialization 169 #region Construction and Initialization
202 public BSScene(string identifier) 170 public BSScene(string engineType, string identifier)
203 { 171 {
204 m_initialized = false; 172 m_initialized = false;
205 // we are passed the name of the region we're working for. 173
174 // The name of the region we're working for is passed to us. Keep for identification.
206 RegionName = identifier; 175 RegionName = identifier;
176
177 // Set identifying variables in the PhysicsScene interface.
178 EngineType = engineType;
179 Name = EngineType + "/" + RegionName;
207 } 180 }
208 181
209 public override void Initialise(IMesher meshmerizer, IConfigSource config) 182 public override void Initialise(IMesher meshmerizer, IConfigSource config)
@@ -216,17 +189,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
216 Shapes = new BSShapeCollection(this); 189 Shapes = new BSShapeCollection(this);
217 190
218 // Allocate pinned memory to pass parameters. 191 // Allocate pinned memory to pass parameters.
219 m_params = new ConfigurationParameters[1]; 192 UnmanagedParams = new ConfigurationParameters[1];
220 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
221 193
222 // Set default values for physics parameters plus any overrides from the ini file 194 // Set default values for physics parameters plus any overrides from the ini file
223 GetInitialParameterValues(config); 195 GetInitialParameterValues(config);
224 196
225 // allocate more pinned memory close to the above in an attempt to get the memory all together 197 // Get the connection to the physics engine (could be native or one of many DLLs)
226 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; 198 PE = SelectUnderlyingBulletEngine(BulletEngineName);
227 m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
228 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
229 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
230 199
231 // Enable very detailed logging. 200 // Enable very detailed logging.
232 // By creating an empty logger when not logging, the log message invocation code 201 // By creating an empty logger when not logging, the log message invocation code
@@ -234,28 +203,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 203 if (m_physicsLoggingEnabled)
235 { 204 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 205 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
206 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 207 }
238 else 208 else
239 { 209 {
240 PhysicsLogging = new Logging.LogWriter(); 210 PhysicsLogging = new Logging.LogWriter();
241 } 211 }
242 212
243 // If Debug logging level, enable logging from the unmanaged code 213 // Allocate memory for returning of the updates and collisions from the physics engine
244 m_DebugLogCallbackHandle = null; 214 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
245 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 215 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
246 {
247 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
248 if (PhysicsLogging.Enabled)
249 // The handle is saved in a variable to make sure it doesn't get freed after this call
250 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
251 else
252 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
253 }
254
255 // Get the version of the DLL
256 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
257 // BulletSimVersion = BulletSimAPI.GetVersion();
258 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
259 216
260 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 217 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
261 // a child in a mega-region. 218 // a child in a mega-region.
@@ -263,18 +220,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
263 // area. It tracks active objects no matter where they are. 220 // area. It tracks active objects no matter where they are.
264 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 221 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
265 222
266 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 223 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
267 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
268 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
269 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
270 m_DebugLogCallbackHandle));
271 224
272 Constraints = new BSConstraintCollection(World); 225 Constraints = new BSConstraintCollection(World);
273 226
274 TerrainManager = new BSTerrainManager(this); 227 TerrainManager = new BSTerrainManager(this);
275 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 228 TerrainManager.CreateInitialGroundPlaneAndTerrain();
276 229
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); 230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
278 231
279 InTaintTime = false; 232 InTaintTime = false;
280 m_initialized = true; 233 m_initialized = true;
@@ -285,9 +238,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
285 private void GetInitialParameterValues(IConfigSource config) 238 private void GetInitialParameterValues(IConfigSource config)
286 { 239 {
287 ConfigurationParameters parms = new ConfigurationParameters(); 240 ConfigurationParameters parms = new ConfigurationParameters();
288 m_params[0] = parms; 241 UnmanagedParams[0] = parms;
289 242
290 SetParameterDefaultValues(); 243 BSParam.SetParameterDefaultValues(this);
291 244
292 if (config != null) 245 if (config != null)
293 { 246 {
@@ -295,19 +248,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
295 IConfig pConfig = config.Configs["BulletSim"]; 248 IConfig pConfig = config.Configs["BulletSim"];
296 if (pConfig != null) 249 if (pConfig != null)
297 { 250 {
298 SetParameterConfigurationValues(pConfig); 251 BSParam.SetParameterConfigurationValues(this, pConfig);
252
253 // There are two Bullet implementations to choose from
254 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
299 255
300 // Very detailed logging for physics debugging 256 // Very detailed logging for physics debugging
257 // TODO: the boolean values can be moved to the normal parameter processing.
301 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 258 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 259 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 260 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 261 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
262 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
263 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
305 // Very detailed logging for vehicle debugging 264 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 265 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
266 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
307 267
308 // Do any replacements in the parameters 268 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 270 }
271
272 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params);
274 if (pConfig != null)
275 {
276 // Let the user add new and interesting material property values.
277 BSMaterials.InitializefromParameters(pConfig);
278 }
311 } 279 }
312 } 280 }
313 281
@@ -326,16 +294,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
326 return ret; 294 return ret;
327 } 295 }
328 296
329 // Called directly from unmanaged code so don't do much 297 // Select the connection to the actual Bullet implementation.
330 private void BulletLogger(string msg) 298 // The main engine selection is the engineName up to the first hypen.
299 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
300 // is passed to the engine to do its special selection, etc.
301 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
331 { 302 {
332 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 303 // For the moment, do a simple switch statement.
333 } 304 // Someday do fancyness with looking up the interfaces in the assembly.
305 BSAPITemplate ret = null;
334 306
335 // Called directly from unmanaged code so don't do much 307 string selectionName = engineName.ToLower();
336 private void BulletLoggerPhysLog(string msg) 308 int hyphenIndex = engineName.IndexOf("-");
337 { 309 if (hyphenIndex > 0)
338 DetailLog("[BULLETS UNMANAGED]:" + msg); 310 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
311
312 switch (selectionName)
313 {
314 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this);
316 break;
317 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this);
319 break;
320 }
321
322 if (ret == null)
323 {
324 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
325 }
326 else
327 {
328 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
329 }
330
331 return ret;
339 } 332 }
340 333
341 public override void Dispose() 334 public override void Dispose()
@@ -345,8 +338,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
345 // make sure no stepping happens while we're deleting stuff 338 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false; 339 m_initialized = false;
347 340
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 341 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 { 342 {
352 kvp.Value.Destroy(); 343 kvp.Value.Destroy();
@@ -366,8 +357,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
366 Shapes = null; 357 Shapes = null;
367 } 358 }
368 359
360 if (TerrainManager != null)
361 {
362 TerrainManager.ReleaseGroundPlaneAndTerrain();
363 TerrainManager.Dispose();
364 TerrainManager = null;
365 }
366
369 // Anything left in the unmanaged code should be cleaned out 367 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr); 368 PE.Shutdown(World);
371 369
372 // Not logging any more 370 // Not logging any more
373 PhysicsLogging.Close(); 371 PhysicsLogging.Close();
@@ -389,12 +387,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
389 if (!m_initialized) return null; 387 if (!m_initialized) return null;
390 388
391 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 389 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
392 lock (PhysObjects) PhysObjects.Add(localID, actor); 390 lock (PhysObjects)
391 PhysObjects.Add(localID, actor);
393 392
394 // TODO: Remove kludge someday. 393 // TODO: Remove kludge someday.
395 // We must generate a collision for avatars whether they collide or not. 394 // We must generate a collision for avatars whether they collide or not.
396 // This is required by OpenSim to update avatar animations, etc. 395 // This is required by OpenSim to update avatar animations, etc.
397 lock (m_avatars) m_avatars.Add(actor); 396 lock (m_avatars)
397 m_avatars.Add(actor);
398 398
399 return actor; 399 return actor;
400 } 400 }
@@ -410,9 +410,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
410 { 410 {
411 try 411 try
412 { 412 {
413 lock (PhysObjects) PhysObjects.Remove(actor.LocalID); 413 lock (PhysObjects)
414 PhysObjects.Remove(bsactor.LocalID);
414 // Remove kludge someday 415 // Remove kludge someday
415 lock (m_avatars) m_avatars.Remove(bsactor); 416 lock (m_avatars)
417 m_avatars.Remove(bsactor);
416 } 418 }
417 catch (Exception e) 419 catch (Exception e)
418 { 420 {
@@ -421,6 +423,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
421 bsactor.Destroy(); 423 bsactor.Destroy();
422 // bsactor.dispose(); 424 // bsactor.dispose();
423 } 425 }
426 else
427 {
428 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
429 LogHeader, actor.LocalID, actor.GetType().Name);
430 }
424 } 431 }
425 432
426 public override void RemovePrim(PhysicsActor prim) 433 public override void RemovePrim(PhysicsActor prim)
@@ -474,41 +481,56 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
474 // Simulate one timestep 481 // Simulate one timestep
475 public override float Simulate(float timeStep) 482 public override float Simulate(float timeStep)
476 { 483 {
484 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f;
486
487 LastTimeStep = timeStep;
488
477 int updatedEntityCount = 0; 489 int updatedEntityCount = 0;
478 IntPtr updatedEntitiesPtr;
479 int collidersCount = 0; 490 int collidersCount = 0;
480 IntPtr collidersPtr;
481 491
482 int beforeTime = 0; 492 int beforeTime = 0;
483 int simTime = 0; 493 int simTime = 0;
484 494
485 // prevent simulation until we've been initialized
486 if (!m_initialized) return 5.0f;
487
488 // update the prim states while we know the physics engine is not busy 495 // update the prim states while we know the physics engine is not busy
489 int numTaints = _taintOperations.Count; 496 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary.
499
500 ProcessTaints();
501
502 // Some of the physical objects requre individual, pre-step calls
503 // (vehicles and avatar movement, in particular)
504 TriggerPreStepEvent(timeStep);
505
506 // the prestep actions might have added taints
507 numTaints += _taintOperations.Count;
490 ProcessTaints(); 508 ProcessTaints();
491 509
492 // Some of the prims operate with special vehicle properties 510 InTaintTime = false; // Only used for debugging so locking is not necessary.
493 ProcessVehicles(timeStep); 511
494 ProcessTaints(); // the vehicles might have added taints 512 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
513 // Only enable this in a limited test world with few objects.
514 if (m_physicsPhysicalDumpEnabled)
515 PE.DumpAllInfo(World);
495 516
496 // step the physical world one interval 517 // step the physical world one interval
497 m_simulationStep++; 518 m_simulationStep++;
498 int numSubSteps = 0; 519 int numSubSteps = 0;
499
500 try 520 try
501 { 521 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 522 if (PhysicsLogging.Enabled)
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 523 beforeTime = Util.EnvironmentTickCount();
504 524
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 525 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
507 526
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 527 if (PhysicsLogging.Enabled)
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 528 {
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 529 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 530 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
531 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
532 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
533 }
512 } 534 }
513 catch (Exception e) 535 catch (Exception e)
514 { 536 {
@@ -520,9 +542,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 542 collidersCount = 0;
521 } 543 }
522 544
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 545 if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
546 PE.DumpPhysicsStatistics(World);
524 547
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 548 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 549 SimulationNowTime = Util.EnvironmentTickCount();
527 550
528 // If there were collisions, process them by sending the event to the prim. 551 // If there were collisions, process them by sending the event to the prim.
@@ -562,12 +585,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 585
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 586 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 587 // Not done above because it is inside an iteration of ObjectWithCollisions.
588 // This complex collision processing is required to create an empty collision
589 // event call after all real collisions have happened on an object. This enables
590 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 591 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 592 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 593 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 594 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 595 ObjectsWithNoMoreCollisions.Clear();
570 } 596 }
597 // Done with collisions.
571 598
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 599 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 600 if (updatedEntityCount > 0)
@@ -583,17 +610,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
583 } 610 }
584 } 611 }
585 612
586 ProcessPostStepTaints(); 613 TriggerPostStepEvent(timeStep);
587 614
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 615 // 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. 616 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 617 if (m_physicsPhysicalDumpEnabled)
618 PE.DumpAllInfo(World);
591 619
592 // The physics engine returns the number of milliseconds it simulated this call. 620 // 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. 621 // 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). 622 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 623 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
596 // return timeStep * 1000 * 55;
597 } 624 }
598 625
599 // Something has collided 626 // Something has collided
@@ -639,12 +666,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 666
640 public override void SetWaterLevel(float baseheight) 667 public override void SetWaterLevel(float baseheight)
641 { 668 {
642 m_waterLevel = baseheight; 669 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 670 }
649 671
650 public override void DeleteTerrain() 672 public override void DeleteTerrain()
@@ -681,6 +703,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
681 public override bool IsThreaded { get { return false; } } 703 public override bool IsThreaded { get { return false; } }
682 704
683 #region Taints 705 #region Taints
706 // The simulation execution order is:
707 // Simulate()
708 // DoOneTimeTaints
709 // TriggerPreStepEvent
710 // DoOneTimeTaints
711 // Step()
712 // ProcessAndForwardCollisions
713 // ProcessAndForwardPropertyUpdates
714 // TriggerPostStepEvent
684 715
685 // Calls to the PhysicsActors can't directly call into the physics engine 716 // Calls to the PhysicsActors can't directly call into the physics engine
686 // because it might be busy. We delay changes to a known time. 717 // because it might be busy. We delay changes to a known time.
@@ -707,58 +738,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 TaintedObject(ident, callback); 738 TaintedObject(ident, callback);
708 } 739 }
709 740
741 private void TriggerPreStepEvent(float timeStep)
742 {
743 PreStepAction actions = BeforeStep;
744 if (actions != null)
745 actions(timeStep);
746
747 }
748
749 private void TriggerPostStepEvent(float timeStep)
750 {
751 PreStepAction actions = AfterStep;
752 if (actions != null)
753 actions(timeStep);
754
755 }
756
710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 757 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
711 // a callback into itself to do the actual property change. That callback is called 758 // a callback into itself to do the actual property change. That callback is called
712 // here just before the physics engine is called to step the simulation. 759 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 760 public void ProcessTaints()
714 { 761 {
715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 762 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 763 ProcessPostTaintTaints();
718 InTaintTime = false;
719 } 764 }
720 765
721 private void ProcessRegularTaints() 766 private void ProcessRegularTaints()
722 { 767 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 768 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
724 { 769 {
725 /*
726 // Code to limit the number of taints processed per step. Meant to limit step time.
727 // Unsure if a good idea as code assumes that taints are done before the step.
728 int taintCount = m_taintsToProcessPerStep;
729 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
730 while (_taintOperations.Count > 0 && taintCount-- > 0)
731 {
732 bool gotOne = false;
733 lock (_taintLock)
734 {
735 if (_taintOperations.Count > 0)
736 {
737 oneCallback = _taintOperations[0];
738 _taintOperations.RemoveAt(0);
739 gotOne = true;
740 }
741 }
742 if (gotOne)
743 {
744 try
745 {
746 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
747 oneCallback.callback();
748 }
749 catch (Exception e)
750 {
751 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
752 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
753 }
754 }
755 }
756 if (_taintOperations.Count > 0)
757 {
758 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
759 }
760 */
761
762 // swizzle a new list into the list location so we can process what's there 770 // swizzle a new list into the list location so we can process what's there
763 List<TaintCallbackEntry> oldList; 771 List<TaintCallbackEntry> oldList;
764 lock (_taintLock) 772 lock (_taintLock)
@@ -797,6 +805,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
797 return; 805 return;
798 } 806 }
799 807
808 // Taints that happen after the normal taint processing but before the simulation step.
800 private void ProcessPostTaintTaints() 809 private void ProcessPostTaintTaints()
801 { 810 {
802 if (_postTaintOperations.Count > 0) 811 if (_postTaintOperations.Count > 0)
@@ -824,45 +833,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
824 } 833 }
825 } 834 }
826 835
827 public void PostStepTaintObject(String ident, TaintCallback callback)
828 {
829 if (!m_initialized) return;
830
831 lock (_taintLock)
832 {
833 _postStepOperations.Add(new TaintCallbackEntry(ident, callback));
834 }
835
836 return;
837 }
838
839 private void ProcessPostStepTaints()
840 {
841 if (_postStepOperations.Count > 0)
842 {
843 List<TaintCallbackEntry> oldList;
844 lock (_taintLock)
845 {
846 oldList = _postStepOperations;
847 _postStepOperations = new List<TaintCallbackEntry>();
848 }
849
850 foreach (TaintCallbackEntry tcbe in oldList)
851 {
852 try
853 {
854 DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
855 tcbe.callback();
856 }
857 catch (Exception e)
858 {
859 m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
860 }
861 }
862 oldList.Clear();
863 }
864 }
865
866 // Only used for debugging. Does not change state of anything so locking is not necessary. 836 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 837 public bool AssertInTaintTime(string whereFrom)
868 { 838 {
@@ -870,517 +840,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
870 { 840 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 841 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
872 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); 842 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
873 Util.PrintCallStack(); // Prints the stack into the DEBUG log file. 843 Util.PrintCallStack(DetailLog);
874 } 844 }
875 return InTaintTime; 845 return InTaintTime;
876 } 846 }
877 847
878 #endregion // Taints 848 #endregion // Taints
879 849
880 #region Vehicles
881
882 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
883 {
884 RemoveVehiclePrim(vehic);
885 if (newType != Vehicle.TYPE_NONE)
886 {
887 // make it so the scene will call us each tick to do vehicle things
888 AddVehiclePrim(vehic);
889 }
890 }
891
892 // Make so the scene will call this prim for vehicle actions each tick.
893 // Safe to call if prim is already in the vehicle list.
894 public void AddVehiclePrim(BSPrim vehicle)
895 {
896 lock (m_vehicles)
897 {
898 if (!m_vehicles.Contains(vehicle))
899 {
900 m_vehicles.Add(vehicle);
901 }
902 }
903 }
904
905 // Remove a prim from our list of vehicles.
906 // Safe to call if the prim is not in the vehicle list.
907 public void RemoveVehiclePrim(BSPrim vehicle)
908 {
909 lock (m_vehicles)
910 {
911 if (m_vehicles.Contains(vehicle))
912 {
913 m_vehicles.Remove(vehicle);
914 }
915 }
916 }
917
918 // Some prims have extra vehicle actions
919 // Called at taint time!
920 private void ProcessVehicles(float timeStep)
921 {
922 foreach (BSPhysObject pobj in m_vehicles)
923 {
924 pobj.StepVehicle(timeStep);
925 }
926 }
927 #endregion Vehicles
928
929 #region INI and command line parameter processing 850 #region INI and command line parameter processing
930 851
931 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
932 delegate float ParamGet(BSScene scene);
933 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
934 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
935
936 private struct ParameterDefn
937 {
938 public string name; // string name of the parameter
939 public string desc; // a short description of what the parameter means
940 public float defaultValue; // default value if not specified anywhere else
941 public ParamUser userParam; // get the value from the configuration file
942 public ParamGet getter; // return the current value stored for this parameter
943 public ParamSet setter; // set the current value for this parameter
944 public SetOnObject onObject; // set the value on an object in the physical domain
945 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
946 {
947 name = n;
948 desc = d;
949 defaultValue = v;
950 userParam = u;
951 getter = g;
952 setter = s;
953 onObject = null;
954 }
955 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
956 {
957 name = n;
958 desc = d;
959 defaultValue = v;
960 userParam = u;
961 getter = g;
962 setter = s;
963 onObject = o;
964 }
965 }
966
967 // List of all of the externally visible parameters.
968 // For each parameter, this table maps a text name to getter and setters.
969 // To add a new externally referencable/settable parameter, add the paramter storage
970 // location somewhere in the program and make an entry in this table with the
971 // getters and setters.
972 // It is easiest to find an existing definition and copy it.
973 // Parameter values are floats. Booleans are converted to a floating value.
974 //
975 // A ParameterDefn() takes the following parameters:
976 // -- the text name of the parameter. This is used for console input and ini file.
977 // -- a short text description of the parameter. This shows up in the console listing.
978 // -- a delegate for fetching the parameter from the ini file.
979 // Should handle fetching the right type from the ini file and converting it.
980 // -- a delegate for getting the value as a float
981 // -- a delegate for setting the value from a float
982 //
983 // The single letter parameters for the delegates are:
984 // s = BSScene
985 // o = BSPhysObject
986 // p = string parameter name
987 // l = localID of referenced object
988 // v = float value
989 // cf = parameter configuration class (for fetching values from ini file)
990 private ParameterDefn[] ParameterDefinitions =
991 {
992 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
993 ConfigurationParameters.numericTrue,
994 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
995 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
996 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
997 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
998 ConfigurationParameters.numericFalse,
999 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
1000 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
1001 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
1002 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
1003 ConfigurationParameters.numericTrue,
1004 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
1005 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
1006 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
1007
1008 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
1009 8f,
1010 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
1011 (s) => { return s.MeshLOD; },
1012 (s,p,l,v) => { s.MeshLOD = v; } ),
1013 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
1014 16f,
1015 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
1016 (s) => { return s.MeshMegaPrimLOD; },
1017 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
1018 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
1019 10f,
1020 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
1021 (s) => { return s.MeshMegaPrimThreshold; },
1022 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
1023 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
1024 32f,
1025 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
1026 (s) => { return s.SculptLOD; },
1027 (s,p,l,v) => { s.SculptLOD = v; } ),
1028
1029 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
1030 10f,
1031 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
1032 (s) => { return (float)s.m_maxSubSteps; },
1033 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
1034 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
1035 1f / 60f,
1036 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
1037 (s) => { return (float)s.m_fixedTimeStep; },
1038 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
1039 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
1040 2048f,
1041 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
1042 (s) => { return (float)s.m_maxCollisionsPerFrame; },
1043 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
1044 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
1045 8000f,
1046 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
1047 (s) => { return (float)s.m_maxUpdatesPerFrame; },
1048 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
1049 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
1050 500f,
1051 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
1052 (s) => { return (float)s.m_taintsToProcessPerStep; },
1053 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
1054 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
1055 10000.01f,
1056 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
1057 (s) => { return (float)s.MaximumObjectMass; },
1058 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
1059
1060 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
1061 2200f,
1062 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
1063 (s) => { return (float)s.PID_D; },
1064 (s,p,l,v) => { s.PID_D = v; } ),
1065 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
1066 900f,
1067 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
1068 (s) => { return (float)s.PID_P; },
1069 (s,p,l,v) => { s.PID_P = v; } ),
1070
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
1076 new ParameterDefn("DefaultDensity", "Density for new objects" ,
1077 10.000006836f, // Aluminum g/cm3
1078 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
1079 (s) => { return s.m_params[0].defaultDensity; },
1080 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
1081 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
1082 0f,
1083 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
1084 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
1091 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
1092 -9.80665f,
1093 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
1094 (s) => { return s.m_params[0].gravity; },
1095 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
1096 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
1097
1098
1099 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
1100 0f,
1101 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
1102 (s) => { return s.m_params[0].linearDamping; },
1103 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
1104 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
1105 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
1106 0f,
1107 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
1108 (s) => { return s.m_params[0].angularDamping; },
1109 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
1110 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
1111 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
1112 0.2f,
1113 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
1114 (s) => { return s.m_params[0].deactivationTime; },
1115 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
1116 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
1117 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
1118 0.8f,
1119 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
1120 (s) => { return s.m_params[0].linearSleepingThreshold; },
1121 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
1122 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
1123 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1124 1.0f,
1125 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
1126 (s) => { return s.m_params[0].angularSleepingThreshold; },
1127 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
1128 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
1129 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1130 0f, // set to zero to disable
1131 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].ccdMotionThreshold; },
1133 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1134 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
1135 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1136 0f,
1137 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1138 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1139 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1140 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
1141 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1142 0.1f,
1143 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1144 (s) => { return s.m_params[0].contactProcessingThreshold; },
1145 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1146 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1147
1148 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
1149 (float)BSTerrainPhys.TerrainImplementation.Mesh,
1150 (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
1151 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1154 0.5f,
1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1156 (s) => { return s.m_params[0].terrainFriction; },
1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
1158 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
1159 0.8f,
1160 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
1161 (s) => { return s.m_params[0].terrainHitFraction; },
1162 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
1163 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
1164 0f,
1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainRestitution; },
1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1169 0.2f,
1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarFriction; },
1172 (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.",
1174 10f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
1178 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1179 60f,
1180 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1181 (s) => { return s.m_params[0].avatarDensity; },
1182 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1183 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1184 0f,
1185 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1186 (s) => { return s.m_params[0].avatarRestitution; },
1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1188 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
1189 0.6f,
1190 (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
1191 (s) => { return s.m_params[0].avatarCapsuleWidth; },
1192 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
1193 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
1194 0.45f,
1195 (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
1196 (s) => { return s.m_params[0].avatarCapsuleDepth; },
1197 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
1198 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1199 1.5f,
1200 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1201 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1202 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1203 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1204 0.1f,
1205 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1208
1209
1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1211 0f,
1212 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1213 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1214 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1215 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1216 0f,
1217 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1218 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1219 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
1220 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1221 ConfigurationParameters.numericFalse,
1222 (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1223 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1224 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1225 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1226 ConfigurationParameters.numericFalse,
1227 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1228 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1229 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1230 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1231 ConfigurationParameters.numericTrue,
1232 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1233 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1234 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1235 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1236 ConfigurationParameters.numericTrue,
1237 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1238 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1239 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1240 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1241 ConfigurationParameters.numericFalse,
1242 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1243 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1244 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1245 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1246 0f, // zero says use Bullet default
1247 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1248 (s) => { return s.m_params[0].numberOfSolverIterations; },
1249 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1250
1251 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1252 (float)BSLinkset.LinksetImplementation.Compound,
1253 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1254 (s) => { return s.m_params[0].linksetImplementation; },
1255 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
1256 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1257 ConfigurationParameters.numericFalse,
1258 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1259 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1260 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1261 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1262 ConfigurationParameters.numericTrue,
1263 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1264 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1265 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1266 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1267 5.0f,
1268 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1269 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1270 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1271 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1272 0.1f,
1273 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1274 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1275 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1276 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1277 0.1f,
1278 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1279 (s) => { return s.m_params[0].linkConstraintCFM; },
1280 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1281 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1282 0.1f,
1283 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1284 (s) => { return s.m_params[0].linkConstraintERP; },
1285 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1286 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1287 40,
1288 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1289 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1290 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1291
1292 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1293 0f,
1294 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1295 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1296 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1297 };
1298
1299 // Convert a boolean to our numeric true and false values
1300 public float NumericBool(bool b)
1301 {
1302 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1303 }
1304
1305 // Convert numeric true and false values to a boolean
1306 public bool BoolNumeric(float b)
1307 {
1308 return (b == ConfigurationParameters.numericTrue ? true : false);
1309 }
1310
1311 // Search through the parameter definitions and return the matching
1312 // ParameterDefn structure.
1313 // Case does not matter as names are compared after converting to lower case.
1314 // Returns 'false' if the parameter is not found.
1315 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1316 {
1317 bool ret = false;
1318 ParameterDefn foundDefn = new ParameterDefn();
1319 string pName = paramName.ToLower();
1320
1321 foreach (ParameterDefn parm in ParameterDefinitions)
1322 {
1323 if (pName == parm.name.ToLower())
1324 {
1325 foundDefn = parm;
1326 ret = true;
1327 break;
1328 }
1329 }
1330 defn = foundDefn;
1331 return ret;
1332 }
1333
1334 // Pass through the settable parameters and set the default values
1335 private void SetParameterDefaultValues()
1336 {
1337 foreach (ParameterDefn parm in ParameterDefinitions)
1338 {
1339 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1340 }
1341 }
1342
1343 // Get user set values out of the ini file.
1344 private void SetParameterConfigurationValues(IConfig cfg)
1345 {
1346 foreach (ParameterDefn parm in ParameterDefinitions)
1347 {
1348 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1349 }
1350 }
1351
1352 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1353
1354 // This creates an array in the correct format for returning the list of
1355 // parameters. This is used by the 'list' option of the 'physics' command.
1356 private void BuildParameterTable()
1357 {
1358 if (SettableParameters.Length < ParameterDefinitions.Length)
1359 {
1360 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1361 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1362 {
1363 ParameterDefn pd = ParameterDefinitions[ii];
1364 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1365 }
1366
1367 // make the list in alphabetical order for estetic reasons
1368 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1369 {
1370 return ppe1.name.CompareTo(ppe2.name);
1371 });
1372
1373 SettableParameters = entries.ToArray();
1374 }
1375 }
1376
1377
1378 #region IPhysicsParameters 852 #region IPhysicsParameters
1379 // Get the list of parameters this physics engine supports 853 // Get the list of parameters this physics engine supports
1380 public PhysParameterEntry[] GetParameterList() 854 public PhysParameterEntry[] GetParameterList()
1381 { 855 {
1382 BuildParameterTable(); 856 BSParam.BuildParameterTable();
1383 return SettableParameters; 857 return BSParam.SettableParameters;
1384 } 858 }
1385 859
1386 // Set parameter on a specific or all instances. 860 // Set parameter on a specific or all instances.
@@ -1392,8 +866,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1392 public bool SetPhysicsParameter(string parm, float val, uint localID) 866 public bool SetPhysicsParameter(string parm, float val, uint localID)
1393 { 867 {
1394 bool ret = false; 868 bool ret = false;
1395 ParameterDefn theParam; 869 BSParam.ParameterDefn theParam;
1396 if (TryGetParameter(parm, out theParam)) 870 if (BSParam.TryGetParameter(parm, out theParam))
1397 { 871 {
1398 theParam.setter(this, parm, localID, val); 872 theParam.setter(this, parm, localID, val);
1399 ret = true; 873 ret = true;
@@ -1405,19 +879,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1405 // If the local ID is APPLY_TO_NONE, just change the default value 879 // If the local ID is APPLY_TO_NONE, just change the default value
1406 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 880 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1407 // If the localID is a specific object, apply the parameter change to only that object 881 // If the localID is a specific object, apply the parameter change to only that object
1408 private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) 882 internal delegate void AssignVal(float x);
883 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
1409 { 884 {
1410 List<uint> objectIDs = new List<uint>(); 885 List<uint> objectIDs = new List<uint>();
1411 switch (localID) 886 switch (localID)
1412 { 887 {
1413 case PhysParameterEntry.APPLY_TO_NONE: 888 case PhysParameterEntry.APPLY_TO_NONE:
1414 defaultLoc = val; // setting only the default value 889 setDefault(val); // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject). 890 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID); 891 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val); 892 TaintedUpdateParameter(parm, objectIDs, val);
1418 break; 893 break;
1419 case PhysParameterEntry.APPLY_TO_ALL: 894 case PhysParameterEntry.APPLY_TO_ALL:
1420 defaultLoc = val; // setting ALL also sets the default value 895 setDefault(val); // setting ALL also sets the default value
1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); 896 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1422 TaintedUpdateParameter(parm, objectIDs, val); 897 TaintedUpdateParameter(parm, objectIDs, val);
1423 break; 898 break;
@@ -1436,8 +911,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1436 List<uint> xlIDs = lIDs; 911 List<uint> xlIDs = lIDs;
1437 string xparm = parm; 912 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() { 913 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam; 914 BSParam.ParameterDefn thisParam;
1440 if (TryGetParameter(xparm, out thisParam)) 915 if (BSParam.TryGetParameter(xparm, out thisParam))
1441 { 916 {
1442 if (thisParam.onObject != null) 917 if (thisParam.onObject != null)
1443 { 918 {
@@ -1458,8 +933,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1458 { 933 {
1459 float val = 0f; 934 float val = 0f;
1460 bool ret = false; 935 bool ret = false;
1461 ParameterDefn theParam; 936 BSParam.ParameterDefn theParam;
1462 if (TryGetParameter(parm, out theParam)) 937 if (BSParam.TryGetParameter(parm, out theParam))
1463 { 938 {
1464 val = theParam.getter(this); 939 val = theParam.getter(this);
1465 ret = true; 940 ret = true;
@@ -1472,22 +947,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1472 947
1473 #endregion Runtime settable parameters 948 #endregion Runtime settable parameters
1474 949
1475 // Debugging routine for dumping detailed physical information for vehicle prims
1476 private void DumpVehicles()
1477 {
1478 foreach (BSPrim prim in m_vehicles)
1479 {
1480 BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
1481 BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
1482 }
1483 }
1484
1485 // Invoke the detailed logger and output something if it's enabled. 950 // Invoke the detailed logger and output something if it's enabled.
1486 public void DetailLog(string msg, params Object[] args) 951 public void DetailLog(string msg, params Object[] args)
1487 { 952 {
1488 PhysicsLogging.Write(msg, args); 953 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 954 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 955 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 956 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 957 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 958 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..838c845 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable
45 // Description of a Mesh 45 // Description of a Mesh
46 private struct MeshDesc 46 private struct MeshDesc
47 { 47 {
48 public IntPtr ptr; 48 public BulletShape shape;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey; 51 public UInt64 shapeKey;
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. 55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc 56 private struct HullDesc
57 { 57 {
58 public IntPtr ptr; 58 public BulletShape shape;
59 public int referenceCount; 59 public int referenceCount;
60 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey; 61 public UInt64 shapeKey;
@@ -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()
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable
91 // higher level dependencies on the shape or body. Mostly used for LinkSets to 98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
92 // remove the physical constraints before the body is destroyed. 99 // remove the physical constraints before the body is destroyed.
93 // Called at taint-time!! 100 // Called at taint-time!!
94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
96 { 103 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
@@ -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, BulletWorld 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 (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
133 { 145 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
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,27 +154,27 @@ 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);
156 168
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 169 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 170 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
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.
164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 176 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 }); 178 });
167 } 179 }
168 } 180 }
@@ -184,17 +196,17 @@ 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
191 { 203 {
192 // This is a new reference to a mesh 204 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 205 meshDesc.shape = shape.Clone();
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,16 +219,16 @@ 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
214 { 226 {
215 // This is a new reference to a hull 227 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 228 hullDesc.shape = shape.Clone();
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,20 +248,20 @@ 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.AddrString, inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape); 263 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
253 } 265 }
254 else 266 else
255 { 267 {
@@ -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 }
@@ -320,57 +332,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 332 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 334 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 335 if (!PhysicsScene.PE.IsCompound(shape))
324 { 336 {
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.AddrString);
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.AddrString);
330 return; 342 return;
331 } 343 }
332 344
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
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 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 350 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 351 DereferenceAnonCollisionShape(childShape);
340 } 352 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 354 }
343 355
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine. 357 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 358 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 359 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 360 {
349 MeshDesc meshDesc; 361 MeshDesc meshDesc;
350 HullDesc hullDesc; 362 HullDesc hullDesc;
351 363
352 BulletShape shapeInfo = new BulletShape(cShape); 364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 365 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 367 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 368 }
358 else 369 else
359 { 370 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 372 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 374 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 375 }
365 else 376 else
366 { 377 {
367 if (BulletSimAPI.IsCompound2(cShape)) 378 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 379 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 381 }
371 else 382 else
372 { 383 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 385 {
375 shapeInfo.isNativeShape = true; 386 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,7 +390,7 @@ public sealed class BSShapeCollection : IDisposable
379 } 390 }
380 } 391 }
381 392
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 394
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 396 {
@@ -388,7 +399,7 @@ public sealed class BSShapeCollection : IDisposable
388 else 399 else
389 { 400 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 403 }
393 } 404 }
394 405
@@ -408,19 +419,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 420 {
410 // an avatar capsule is close to a native shape (it is not shared) 421 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 424 ret = true;
415 haveShape = true; 425 haveShape = true;
416 } 426 }
417 427
418 // Compound shapes are handled special as they are rebuilt from scratch. 428 // 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. 429 // 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) 430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 431 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 434 haveShape = true;
425 } 435 }
426 436
@@ -433,7 +443,7 @@ public sealed class BSShapeCollection : IDisposable
433 } 443 }
434 444
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 445 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 446 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 447 {
438 bool ret = false; 448 bool ret = false;
439 bool haveShape = false; 449 bool haveShape = false;
@@ -443,8 +453,9 @@ public sealed class BSShapeCollection : IDisposable
443 // If the prim attributes are simple, this could be a simple Bullet native shape 453 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 454 if (!haveShape
445 && pbs != null 455 && pbs != null
456 && !pbs.SculptEntry
446 && nativeShapePossible 457 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 458 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 459 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
449 && pbs.ProfileHollow == 0 460 && pbs.ProfileHollow == 0
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 461 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
@@ -453,19 +464,27 @@ public sealed class BSShapeCollection : IDisposable
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 464 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 465 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 { 466 {
467 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
468 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
469 if (prim.PhysShape.HasPhysicalShape)
470 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
471
472 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
473 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
474
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 475 // 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) 476 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 477 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 478 {
460 haveShape = true; 479 haveShape = true;
461 if (forceRebuild 480 if (forceRebuild
462 || prim.Scale != prim.Size 481 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 482 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 483 )
465 { 484 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 485 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 486 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 487 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape); 488 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 489 }
471 } 490 }
@@ -473,13 +492,13 @@ public sealed class BSShapeCollection : IDisposable
473 { 492 {
474 haveShape = true; 493 haveShape = true;
475 if (forceRebuild 494 if (forceRebuild
476 || prim.Scale != prim.Size 495 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 496 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 497 )
479 { 498 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 499 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 500 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 501 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape); 502 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 503 }
485 } 504 }
@@ -500,17 +519,17 @@ public sealed class BSShapeCollection : IDisposable
500 bool ret = false; 519 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 520 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 521 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 522 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 523 {
505 // Update prim.BSShape to reference a hull of this shape. 524 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 525 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 526 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 527 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 528 }
510 else 529 else
511 { 530 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 531 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 532 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 533 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 534 }
516 return ret; 535 return ret;
@@ -528,9 +547,10 @@ public sealed class BSShapeCollection : IDisposable
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 547 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 548
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 549 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 550 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 551 prim.LocalID, newShape, prim.Scale);
533 552
553 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 554 prim.PhysShape = newShape;
535 return true; 555 return true;
536 } 556 }
@@ -550,20 +570,17 @@ public sealed class BSShapeCollection : IDisposable
550 570
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 571 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 572 {
553 // The proper scale has been calculated in the prim. 573
554 newShape = new BulletShape( 574 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 575 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 576 }
559 else 577 else
560 { 578 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 579 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 580 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 581
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 582 }
566 if (newShape.ptr == IntPtr.Zero) 583 if (!newShape.HasPhysicalShape)
567 { 584 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 585 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 586 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +597,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 597 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 598 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 599 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 600 BulletShape newShape = new BulletShape();
584 601
585 float lod; 602 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 603 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,7 +606,7 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 606 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 607 return false;
591 608
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 609 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 610 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594 611
595 // Since we're recreating new, get rid of the reference to the previous shape 612 // Since we're recreating new, get rid of the reference to the previous shape
@@ -601,8 +618,6 @@ public sealed class BSShapeCollection : IDisposable
601 618
602 ReferenceShape(newShape); 619 ReferenceShape(newShape);
603 620
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 621 prim.PhysShape = newShape;
607 622
608 return true; // 'true' means a new shape has been added to this prim 623 return true; // 'true' means a new shape has been added to this prim
@@ -610,18 +625,18 @@ public sealed class BSShapeCollection : IDisposable
610 625
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 626 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 627 {
628 BulletShape newShape = new BulletShape();
613 IMesh meshData = null; 629 IMesh meshData = null;
614 IntPtr meshPtr = IntPtr.Zero; 630
615 MeshDesc meshDesc; 631 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 632 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 { 633 {
618 // If the mesh has already been built just use it. 634 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr; 635 newShape = meshDesc.shape.Clone();
620 } 636 }
621 else 637 else
622 { 638 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 639 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625 640
626 if (meshData != null) 641 if (meshData != null)
627 { 642 {
@@ -640,11 +655,10 @@ public sealed class BSShapeCollection : IDisposable
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 655 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 656 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
642 657
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 658 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 659 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
645 } 660 }
646 } 661 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 662 newShape.shapeKey = newMeshKey;
649 663
650 return newShape; 664 return newShape;
@@ -663,7 +677,7 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 677 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 678 return false;
665 679
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 680 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 681 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 682
669 // Remove usage of the previous shape. 683 // Remove usage of the previous shape.
@@ -674,8 +688,6 @@ public sealed class BSShapeCollection : IDisposable
674 688
675 ReferenceShape(newShape); 689 ReferenceShape(newShape);
676 690
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 691 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 692 return true; // 'true' means a new shape has been added to this prim
681 } 693 }
@@ -684,18 +696,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 696 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 697 {
686 698
699 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 700 IntPtr hullPtr = IntPtr.Zero;
701
688 HullDesc hullDesc; 702 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 703 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 704 {
691 // If the hull shape already is created, just use it. 705 // If the hull shape already is created, just use it.
692 hullPtr = hullDesc.ptr; 706 newShape = hullDesc.shape.Clone();
693 } 707 }
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
@@ -777,14 +791,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 791 }
778 } 792 }
779 // create the hull data structure in Bullet 793 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 794 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 795 }
782 } 796 }
783 797
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 798 newShape.shapeKey = newHullKey;
786 799
787 return newShape; // 'true' means a new shape has been added to this prim 800 return newShape;
788 } 801 }
789 802
790 // Callback from convex hull creater with a newly created hull. 803 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +816,13 @@ public sealed class BSShapeCollection : IDisposable
803 // Don't need to do this as the shape is freed when the new root shape is created below. 816 // Don't need to do this as the shape is freed when the new root shape is created below.
804 // DereferenceShape(prim.PhysShape, true, shapeCallback); 817 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 818
806 BulletShape cShape = new BulletShape( 819
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); 820 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
808 821
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 822 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 823 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 824 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 825 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 826 prim.LocalID, cShape, prim.PhysShape);
814 827
815 prim.PhysShape = cShape; 828 prim.PhysShape = cShape;
@@ -822,14 +835,14 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 835 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 836 {
824 // level of detail based on size and type of the object 837 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 838 float lod = BSParam.MeshLOD;
826 if (pbs.SculptEntry) 839 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 840 lod = BSParam.SculptLOD;
828 841
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 842 // Mega prims usually get more detail because one can interact with shape approximations at this size.
830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); 843 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 844 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 845 lod = BSParam.MeshMegaPrimLOD;
833 846
834 retLod = lod; 847 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 848 return pbs.GetMeshKey(size, lod);
@@ -851,7 +864,7 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 864 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 865 {
853 // If the shape was successfully created, nothing more to do 866 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 867 if (newShape.HasPhysicalShape)
855 return newShape; 868 return newShape;
856 869
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 870 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@@ -893,7 +906,7 @@ public sealed class BSShapeCollection : IDisposable
893 } 906 }
894 } 907 }
895 908
896 // While we figure out the real problem, stick a simple native shape on the object. 909 // While we figure out the real problem, stick in a simple box for the object.
897 BulletShape fillinShape = 910 BulletShape fillinShape =
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 911 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
899 912
@@ -904,19 +917,19 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 917 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 918 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 919 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 920 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
908 BodyDestructionCallback bodyCallback) 921 BodyDestructionCallback bodyCallback)
909 { 922 {
910 bool ret = false; 923 bool ret = false;
911 924
912 // the mesh, hull or native shape must have already been created in Bullet 925 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 926 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 927
915 // If there is an existing body, verify it's of an acceptable type. 928 // 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. 929 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 930 if (!mustRebuild)
918 { 931 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 932 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 933 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 934 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 935 {
@@ -931,20 +944,16 @@ public sealed class BSShapeCollection : IDisposable
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 944 DereferenceBody(prim.PhysBody, true, bodyCallback);
932 945
933 BulletBody aBody; 946 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 947 if (prim.IsSolid)
936 { 948 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 949 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 950 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 } 951 }
941 else 952 else
942 { 953 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 954 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 955 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 } 956 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 957
949 ReferenceBody(aBody, true); 958 ReferenceBody(aBody, true);
950 959
@@ -956,13 +965,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 965 return ret;
957 } 966 }
958 967
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 968 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 969 {
961 bool ret = false; 970 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 971 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 972 foreach (MeshDesc md in Meshes.Values)
964 { 973 {
965 if (md.ptr == addr) 974 if (md.shape.ReferenceSame(shape))
966 { 975 {
967 foundDesc = md; 976 foundDesc = md;
968 ret = true; 977 ret = true;
@@ -974,13 +983,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 983 return ret;
975 } 984 }
976 985
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 986 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 987 {
979 bool ret = false; 988 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 989 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 990 foreach (HullDesc hd in Hulls.Values)
982 { 991 {
983 if (hd.ptr == addr) 992 if (hd.shape.ReferenceSame(shape))
984 { 993 {
985 foundDesc = hd; 994 foundDesc = hd;
986 ret = true; 995 ret = true;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index 96cd55e..ee18379 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -27,24 +27,19 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Text; 30using System.Text;
32 31
32using OMV = OpenMetaverse;
33
33namespace OpenSim.Region.Physics.BulletSPlugin 34namespace OpenSim.Region.Physics.BulletSPlugin
34{ 35{
35public abstract class BSShape 36public abstract class BSShape
36{ 37{
37 public IntPtr ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; } 38 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; } 39 public DateTime lastReferenced { get; set; }
42 40
43 public BSShape() 41 public BSShape()
44 { 42 {
45 ptr = IntPtr.Zero;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0; 43 referenceCount = 0;
49 lastReferenced = DateTime.Now; 44 lastReferenced = DateTime.Now;
50 } 45 }
@@ -63,7 +58,7 @@ public abstract class BSShape
63 } 58 }
64 59
65 // Compound shapes are handled special as they are rebuilt from scratch. 60 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created. 61 // This isn't too great a hardship since most of the child shapes will have already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 62 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 { 63 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added 64 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
@@ -71,6 +66,14 @@ public abstract class BSShape
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); 66 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 } 67 }
73 68
69 // Avatars have their own unique shape
70 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
71 {
72 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
73 ret = BSShapeAvatar.GetReference(prim);
74 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
75 }
76
74 if (ret == null) 77 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 78 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76 79
@@ -91,15 +94,17 @@ public abstract class BSShape
91 // All shapes have a static call to get a reference to the physical shape 94 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference(); 95 // protected abstract static BSShape GetReference();
93 96
97 // Returns a string for debugging that uniquily identifies the memory used by this instance
98 public virtual string AddrString
99 {
100 get { return "unknown"; }
101 }
102
94 public override string ToString() 103 public override string ToString()
95 { 104 {
96 StringBuilder buff = new StringBuilder(); 105 StringBuilder buff = new StringBuilder();
97 buff.Append("<p="); 106 buff.Append("<p=");
98 buff.Append(ptr.ToString("X")); 107 buff.Append(AddrString);
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c="); 108 buff.Append(",c=");
104 buff.Append(referenceCount.ToString()); 109 buff.Append(referenceCount.ToString());
105 buff.Append(">"); 110 buff.Append(">");
@@ -126,7 +131,8 @@ public class BSShapeNative : BSShape
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 131 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 { 132 {
128 // Native shapes are not shared and are always built anew. 133 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 134 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
135 return null;
130 } 136 }
131 137
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 138 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
@@ -141,14 +147,15 @@ public class BSShapeNative : BSShape
141 nativeShapeData.HullKey = (ulong)shapeKey; 147 nativeShapeData.HullKey = (ulong)shapeKey;
142 148
143 149
150 /*
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 151 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 { 152 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); 153 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 154 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 } 155 }
149 else 156 else
150 { 157 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); 158 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
152 } 159 }
153 if (ptr == IntPtr.Zero) 160 if (ptr == IntPtr.Zero)
154 { 161 {
@@ -157,15 +164,18 @@ public class BSShapeNative : BSShape
157 } 164 }
158 type = shapeType; 165 type = shapeType;
159 key = (UInt64)shapeKey; 166 key = (UInt64)shapeKey;
167 */
160 } 168 }
161 // Make this reference to the physical shape go away since native shapes are not shared. 169 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene) 170 public override void Dereference(BSScene physicsScene)
163 { 171 {
172 /*
164 // Native shapes are not tracked and are released immediately 173 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 174 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); 175 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
167 ptr = IntPtr.Zero; 176 ptr = IntPtr.Zero;
168 // Garbage collection will free up this instance. 177 // Garbage collection will free up this instance.
178 */
169 } 179 }
170} 180}
171 181
@@ -205,4 +215,143 @@ public class BSShapeCompound : BSShape
205 } 215 }
206 public override void Dereference(BSScene physicsScene) { } 216 public override void Dereference(BSScene physicsScene) { }
207} 217}
218
219public class BSShapeAvatar : BSShape
220{
221 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
222 public BSShapeAvatar() : base()
223 {
224 }
225 public static BSShape GetReference(BSPhysObject prim)
226 {
227 return new BSShapeNull();
228 }
229 public override void Dereference(BSScene physicsScene) { }
230
231 // From the front:
232 // A---A
233 // / \
234 // B-------B
235 // / \ +Z
236 // C-----------C |
237 // \ / -Y --+-- +Y
238 // \ / |
239 // \ / -Z
240 // D-----D
241 // \ /
242 // E-E
243
244 // From the top A and E are just lines.
245 // B, C and D are hexagons:
246 //
247 // C1--C2 +X
248 // / \ |
249 // C0 C3 -Y --+-- +Y
250 // \ / |
251 // C5--C4 -X
252
253 // Zero goes directly through the middle so the offsets are from that middle axis
254 // and up and down from a middle horizon (A and E are the same distance from the zero).
255 // The height, width and depth is one. All scaling is done by the simulator.
256
257 // Z component -- how far the level is from the middle zero
258 private const float Aup = 0.5f;
259 private const float Bup = 0.4f;
260 private const float Cup = 0.3f;
261 private const float Dup = -0.4f;
262 private const float Eup = -0.5f;
263
264 // Y component -- distance from center to x0 and x3
265 private const float Awid = 0.25f;
266 private const float Bwid = 0.3f;
267 private const float Cwid = 0.5f;
268 private const float Dwid = 0.3f;
269 private const float Ewid = 0.2f;
270
271 // Y component -- distance from center to x1, x2, x4 and x5
272 private const float Afwid = 0.0f;
273 private const float Bfwid = 0.2f;
274 private const float Cfwid = 0.4f;
275 private const float Dfwid = 0.2f;
276 private const float Efwid = 0.0f;
277
278 // X component -- distance from zero to the front or back of a level
279 private const float Adep = 0f;
280 private const float Bdep = 0.3f;
281 private const float Cdep = 0.5f;
282 private const float Ddep = 0.2f;
283 private const float Edep = 0f;
284
285 private OMV.Vector3[] avatarVertices = {
286 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
287 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
288
289 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
290 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
291 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
292 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
293 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
294 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
295
296 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
297 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
298 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
299 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
300 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
301 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
302
303 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
304 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
305 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
306 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
307 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
308 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
309
310 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
311 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
312 };
313
314 // Offsets of the vertices in the vertices array
315 private enum Ind : int
316 {
317 A0, A3,
318 B0, B1, B2, B3, B4, B5,
319 C0, C1, C2, C3, C4, C5,
320 D0, D1, D2, D3, D4, D5,
321 E0, E3
322 }
323
324 // Comments specify trianges and quads in clockwise direction
325 private Ind[] avatarIndices = {
326 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
327 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
328 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
329 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
330 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
331 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
332
333 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
334 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
335 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
336 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
337 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
338 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
339
340 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
341 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
342 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
343 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
344 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
345 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
346
347 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
348 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
349 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
350 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
351 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
352 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
353
354 };
355
356}
208} 357}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756c..e4fecc3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -44,7 +44,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
44{ 44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; 45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46 46
47 BulletHeightMapInfo m_mapInfo = null; 47 BulletHMapInfo m_mapInfo = null;
48 48
49 // Constructor to build a default, flat heightmap terrain. 49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) 50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
@@ -58,7 +58,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
58 { 58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; 59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 } 60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); 61 m_mapInfo = new BulletHMapInfo(id, initialMap);
62 m_mapInfo.minCoords = minTerrainCoords; 62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords; 63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase; 64 m_mapInfo.terrainRegionBase = TerrainBase;
@@ -72,7 +72,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
72 Vector3 minCoords, Vector3 maxCoords) 72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 73 : base(physicsScene, regionBase, id)
74 { 74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); 75 m_mapInfo = new BulletHMapInfo(id, initialMap);
76 m_mapInfo.minCoords = minCoords; 76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords; 77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z; 78 m_mapInfo.minZ = minCoords.Z;
@@ -91,13 +91,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
91 // Using the information in m_mapInfo, create the physical representation of the heightmap. 91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain() 92 private void BuildHeightmapTerrain()
93 { 93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
97
98 // Create the terrain shape from the mapInfo 94 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
100 BSPhysicsShapeType.SHAPE_TERRAIN); 96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98
101 99
102 // The terrain object initial position is at the center of the object 100 // The terrain object initial position is at the center of the object
103 Vector3 centerPos; 101 Vector3 centerPos;
@@ -105,28 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
107 105
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, 106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, 107 m_mapInfo.ID, centerPos, Quaternion.Identity);
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111 108
112 // Set current terrain attributes 109 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); 110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
117 114
118 // Return the new terrain to the world of physical objects 115 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody);
120 117
121 // redo its bounding box now that it is in the world 118 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody);
123 120
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, 121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 (uint)CollisionFilterGroups.TerrainFilter, 122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
126 (uint)CollisionFilterGroups.TerrainMask);
127 123
128 // Make it so the terrain will not move or be considered for movement. 124 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
130 126
131 return; 127 return;
132 } 128 }
@@ -136,19 +132,18 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
136 { 132 {
137 if (m_mapInfo != null) 133 if (m_mapInfo != null)
138 { 134 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) 135 if (m_mapInfo.terrainBody.HasPhysicalBody)
140 { 136 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody);
142 // Frees both the body and the shape. 138 // Frees both the body and the shape.
143 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody);
144 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
145 } 140 }
146 } 141 }
147 m_mapInfo = null; 142 m_mapInfo = null;
148 } 143 }
149 144
150 // The passed position is relative to the base of the region. 145 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos) 146 public override float GetTerrainHeightAtXYZ(Vector3 pos)
152 { 147 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 148 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154 149
@@ -166,5 +161,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
166 } 161 }
167 return ret; 162 return ret;
168 } 163 }
164
165 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 {
168 return PhysicsScene.SimpleWaterLevel;
169 }
169} 170}
170} 171}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd3..2e9db39 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,25 +122,28 @@ 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.
128 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
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 = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 139
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
136 Vector3.Zero, Quaternion.Identity)); 141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
137 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
138 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
139 // Ground plane does not move 142 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 144 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 145 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
144 147
145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 148 // 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); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -150,13 +153,13 @@ public sealed class BSTerrainManager
150 // Release all the terrain structures we might have allocated 153 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 154 public void ReleaseGroundPlaneAndTerrain()
152 { 155 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 156 if (m_groundPlane.HasPhysicalBody)
154 { 157 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
156 { 159 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
158 } 161 }
159 m_groundPlane.ptr = IntPtr.Zero; 162 m_groundPlane.Clear();
160 } 163 }
161 164
162 ReleaseTerrain(); 165 ReleaseTerrain();
@@ -165,17 +168,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 168 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 169 public void ReleaseTerrain()
167 { 170 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 171 lock (m_terrains)
169 { 172 {
170 kvp.Value.Dispose(); 173 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
174 {
175 kvp.Value.Dispose();
176 }
177 m_terrains.Clear();
171 } 178 }
172 m_terrains.Clear();
173 } 179 }
174 180
175 // The simulator wants to set a new heightmap for the terrain. 181 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 182 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 183 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 184 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 187 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 189 {
@@ -211,6 +219,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 219 // 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. 220 // 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.) 221 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 223 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 225 {
@@ -220,7 +229,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 229 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 230 // 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 231 // 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. 232 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 233 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 234 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 235 foreach (float height in heightMap)
@@ -238,15 +247,15 @@ public sealed class BSTerrainManager
238 247
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 249
241 BSTerrainPhys terrainPhys; 250 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 251 {
244 // There is already a terrain in this spot. Free the old and build the new. 252 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 254 {
255 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258
250 // Remove old terrain from the collection 259 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 260 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 261 // Release any physical memory it may be using.
@@ -271,35 +280,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 280 // I hate doing this, but just bail
272 return; 281 return;
273 } 282 }
274 }); 283 }
275 } 284 else
276 else 285 {
277 { 286 // 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 287 // 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 288
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 289 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 290 uint newTerrainID = id;
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount;
292 293
293 // Code that must happen at taint-time 294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 295 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); 296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 297 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 298
301 m_terrainModified = true; 299 m_terrainModified = true;
302 }); 300 }
303 } 301 }
304 } 302 }
305 303
@@ -308,9 +306,9 @@ public sealed class BSTerrainManager
308 { 306 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 308 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); 309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
312 BSTerrainPhys newTerrainPhys = null; 310 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation) 311 switch ((int)BSParam.TerrainImplementation)
314 { 312 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@@ -323,14 +321,21 @@ public sealed class BSTerrainManager
323 default: 321 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader, 323 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation, 324 (int)BSParam.TerrainImplementation,
327 PhysicsScene.Params.terrainImplementation, 325 BSParam.TerrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase); 326 PhysicsScene.RegionName, terrainRegionBase);
329 break; 327 break;
330 } 328 }
331 return newTerrainPhys; 329 return newTerrainPhys;
332 } 330 }
333 331
332 // Return 'true' of this position is somewhere in known physical terrain space
333 public bool IsWithinKnownTerrain(Vector3 pos)
334 {
335 Vector3 terrainBaseXYZ;
336 BSTerrainPhys physTerrain;
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 }
334 339
335 // Given an X and Y, find the height of the terrain. 340 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 341 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +346,74 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 346 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 347 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 348 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 349 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 350 {
346 float tX = loc.X; 351 float tX = pos.X;
347 float tY = loc.Y; 352 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 353 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 354 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 355 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 356 return lastHeight;
357 m_terrainModified = false;
352 358
353 lastHeightTX = tX; 359 lastHeightTX = tX;
354 lastHeightTY = tY; 360 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 361 float ret = HEIGHT_GETHEIGHT_RET;
356 362
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 363 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; 364 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 365 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 366 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 367 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 368 }
368 else 369 else
369 { 370 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 372 LogHeader, PhysicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 375 }
373 m_terrainModified = false; 376
374 lastHeight = ret; 377 lastHeight = ret;
375 return ret; 378 return ret;
376 } 379 }
377 380
381 public float GetWaterLevelAtXYZ(Vector3 pos)
382 {
383 float ret = WATER_HEIGHT_GETHEIGHT_RET;
384
385 Vector3 terrainBaseXYZ;
386 BSTerrainPhys physTerrain;
387 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
388 {
389 ret = physTerrain.GetWaterLevelAtXYZ(pos);
390 }
391 else
392 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 }
396 return ret;
397 }
398
399 // Given an address, return 'true' of there is a description of that terrain and output
400 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
406
407 BSTerrainPhys physTerrain = null;
408 lock (m_terrains)
409 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 }
412 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain;
414 return (physTerrain != null);
415 }
416
378 // Although no one seems to check this, I do support combining. 417 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 418 public bool SupportsCombining()
380 { 419 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..8244f02 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,11 +88,11 @@ 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 = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
93 indicesCount, indices, verticesCount, vertices), 95 if (!m_terrainShape.HasPhysicalShape)
94 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 96 {
97 // DISASTER!! 97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@@ -104,8 +104,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
104 Vector3 pos = regionBase; 104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity; 105 Quaternion rot = Quaternion.Identity;
106 106
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 107 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (m_terrainBody.ptr == IntPtr.Zero) 108 if (!m_terrainBody.HasPhysicalBody)
109 { 109 {
110 // DISASTER!! 110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@@ -114,39 +114,40 @@ public sealed class BSTerrainMesh : BSTerrainPhys
114 } 114 }
115 115
116 // Set current terrain attributes 116 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); 117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 121
122 // Static objects are not very massive. 122 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 123 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124 124
125 // Return the new terrain to the world of physical objects 125 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 126 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127 127
128 // redo its bounding box now that it is in the world 128 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 129 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130 130
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 131 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 132 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133 (uint)CollisionFilterGroups.TerrainMask);
134 133
135 // Make it so the terrain will not move or be considered for movement. 134 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 135 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
137 } 136 }
138 137
139 public override void Dispose() 138 public override void Dispose()
140 { 139 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 140 if (m_terrainBody.HasPhysicalBody)
142 { 141 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 142 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
144 // Frees both the body and the shape. 143 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
145 m_terrainBody.Clear();
146 m_terrainShape.Clear();
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
deleted file mode 100644
index e60a760..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ /dev/null
@@ -1,1015 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above 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.Runtime.InteropServices;
29using System.Security;
30using System.Text;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin {
34
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
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
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// ===============================================================================
174[StructLayout(LayoutKind.Sequential)]
175public struct ConvexHull
176{
177 Vector3 Offset;
178 int VertexCount;
179 Vector3[] Vertices;
180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
209[StructLayout(LayoutKind.Sequential)]
210public struct ShapeData
211{
212 public uint ID;
213 public BSPhysicsShapeType Type;
214 public Vector3 Position;
215 public Quaternion Rotation;
216 public Vector3 Velocity;
217 public Vector3 Scale;
218 public float Mass;
219 public float Buoyancy;
220 public System.UInt64 HullKey;
221 public System.UInt64 MeshKey;
222 public float Friction;
223 public float Restitution;
224 public float Collidable; // true of things bump into this
225 public float Static; // true if a static object. Otherwise gravity, etc.
226 public float Solid; // true if object cannot be passed through
227 public Vector3 Size;
228
229 // note that bools are passed as floats since bool size changes by language and architecture
230 public const float numericTrue = 1f;
231 public const float numericFalse = 0f;
232}
233[StructLayout(LayoutKind.Sequential)]
234public struct SweepHit
235{
236 public uint ID;
237 public float Fraction;
238 public Vector3 Normal;
239 public Vector3 Point;
240}
241[StructLayout(LayoutKind.Sequential)]
242public struct RaycastHit
243{
244 public uint ID;
245 public float Fraction;
246 public Vector3 Normal;
247}
248[StructLayout(LayoutKind.Sequential)]
249public struct CollisionDesc
250{
251 public uint aID;
252 public uint bID;
253 public Vector3 point;
254 public Vector3 normal;
255}
256[StructLayout(LayoutKind.Sequential)]
257public struct EntityProperties
258{
259 public uint ID;
260 public Vector3 Position;
261 public Quaternion Rotation;
262 public Vector3 Velocity;
263 public Vector3 Acceleration;
264 public Vector3 RotationalVelocity;
265}
266
267// Format of this structure must match the definition in the C++ code
268[StructLayout(LayoutKind.Sequential)]
269public struct ConfigurationParameters
270{
271 public float defaultFriction;
272 public float defaultDensity;
273 public float defaultRestitution;
274 public float collisionMargin;
275 public float gravity;
276
277 public float linearDamping;
278 public float angularDamping;
279 public float deactivationTime;
280 public float linearSleepingThreshold;
281 public float angularSleepingThreshold;
282 public float ccdMotionThreshold;
283 public float ccdSweptSphereRadius;
284 public float contactProcessingThreshold;
285
286 public float terrainImplementation;
287 public float terrainFriction;
288 public float terrainHitFraction;
289 public float terrainRestitution;
290 public float avatarFriction;
291 public float avatarStandingFriction;
292 public float avatarDensity;
293 public float avatarRestitution;
294 public float avatarCapsuleWidth;
295 public float avatarCapsuleDepth;
296 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold;
298
299 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation;
302 public float shouldForceUpdateAllAabbs;
303 public float shouldRandomizeSolverOrder;
304 public float shouldSplitSimulationIslands;
305 public float shouldEnableFrictionCaching;
306 public float numberOfSolverIterations;
307
308 public float linksetImplementation;
309 public float linkConstraintUseFrameOffset;
310 public float linkConstraintEnableTransMotor;
311 public float linkConstraintTransMotorMaxVel;
312 public float linkConstraintTransMotorMaxForce;
313 public float linkConstraintERP;
314 public float linkConstraintCFM;
315 public float linkConstraintSolverIterations;
316
317 public float physicsLoggingFrames;
318
319 public const float numericTrue = 1f;
320 public const float numericFalse = 0f;
321}
322
323
324// The states a bullet collision object can have
325public enum ActivationState : uint
326{
327 ACTIVE_TAG = 1,
328 ISLAND_SLEEPING,
329 WANTS_DEACTIVATION,
330 DISABLE_DEACTIVATION,
331 DISABLE_SIMULATION,
332}
333
334public enum CollisionObjectTypes : int
335{
336 CO_COLLISION_OBJECT = 1 << 0,
337 CO_RIGID_BODY = 1 << 1,
338 CO_GHOST_OBJECT = 1 << 2,
339 CO_SOFT_BODY = 1 << 3,
340 CO_HF_FLUID = 1 << 4,
341 CO_USER_TYPE = 1 << 5,
342}
343
344// Values used by Bullet and BulletSim to control object properties.
345// Bullet's "CollisionFlags" has more to do with operations on the
346// object (if collisions happen, if gravity effects it, ...).
347public enum CollisionFlags : uint
348{
349 CF_STATIC_OBJECT = 1 << 0,
350 CF_KINEMATIC_OBJECT = 1 << 1,
351 CF_NO_CONTACT_RESPONSE = 1 << 2,
352 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
353 CF_CHARACTER_OBJECT = 1 << 4,
354 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
356 // Following used by BulletSim to control collisions
357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
358 BS_FLOATS_ON_WATER = 1 << 11,
359 BS_NONE = 0,
360 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};
368
369// Values for collisions groups and masks
370public enum CollisionFilterGroups : uint
371{
372 // Don't use the bit definitions!! Define the use in a
373 // filter/mask definition below. This way collision interactions
374 // are more easily debugged.
375 BNoneFilter = 0,
376 BDefaultFilter = 1 << 0,
377 BStaticFilter = 1 << 1,
378 BKinematicFilter = 1 << 2,
379 BDebrisFilter = 1 << 3,
380 BSensorTrigger = 1 << 4,
381 BCharacterFilter = 1 << 5,
382 BAllFilter = 0xFFFFFFFF,
383 // Filter groups defined by BulletSim
384 BGroundPlaneFilter = 1 << 10,
385 BTerrainFilter = 1 << 11,
386 BRaycastFilter = 1 << 12,
387 BSolidFilter = 1 << 13,
388 BLinksetFilter = 1 << 14,
389
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};
407
408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
409// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
410public enum ConstraintParams : int
411{
412 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
413 BT_CONSTRAINT_STOP_ERP,
414 BT_CONSTRAINT_CFM,
415 BT_CONSTRAINT_STOP_CFM,
416};
417public enum ConstraintParamAxis : int
418{
419 AXIS_LINEAR_X = 0,
420 AXIS_LINEAR_Y,
421 AXIS_LINEAR_Z,
422 AXIS_ANGULAR_X,
423 AXIS_ANGULAR_Y,
424 AXIS_ANGULAR_Z,
425 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
426 AXIS_ANGULAR_ALL,
427 AXIS_ALL
428};
429
430// ===============================================================================
431static class BulletSimAPI {
432
433// Link back to the managed code for outputting log messages
434[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
436
437// ===============================================================================
438// Initialization and simulation
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
440public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
441 int maxCollisions, IntPtr collisionArray,
442 int maxUpdates, IntPtr updateArray,
443 DebugLogCallback logRoutine);
444
445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
446public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
447
448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
449public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
450
451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
452public static extern void Shutdown2(IntPtr sim);
453
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
456 out int updatedEntityCount,
457 out IntPtr updatedEntitiesPtr,
458 out int collidersCount,
459 out IntPtr collidersPtr);
460
461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
462public static extern bool PushUpdate2(IntPtr obj);
463
464// =====================================================================================
465// Mesh, hull, shape and body creation helper routines
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern IntPtr CreateMeshShape2(IntPtr world,
468 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
470
471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
472public static extern IntPtr CreateHullShape2(IntPtr world,
473 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool IsNativeShape2(IntPtr shape);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
489
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
492
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
495
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
498
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
501
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
504
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
507
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
510
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
513
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
516
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern int GetBodyType2(IntPtr obj);
519
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
522
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
525
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
528
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
531
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern void ReleaseBodyInfo2(IntPtr obj);
534
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
537
538// =====================================================================================
539// Terrain creation and helper routines
540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
541public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
542 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
543
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
546 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
547
548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
549public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
550
551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
552public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
553
554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
555public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
556
557// =====================================================================================
558// Constraint creation and helper routines
559[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
560public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
561 Vector3 frame1loc, Quaternion frame1rot,
562 Vector3 frame2loc, Quaternion frame2rot,
563 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
564
565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
566public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
567 Vector3 joinPoint,
568 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
569
570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
571public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
572 Vector3 pivotinA, Vector3 pivotinB,
573 Vector3 axisInA, Vector3 axisInB,
574 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
575
576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
577public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
578
579[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
580public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
581
582[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
583public static extern bool SetFrames2(IntPtr constrain,
584 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
585
586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
587public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
588
589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
590public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
591
592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
593public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
594
595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
596public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
597
598[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
599public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
600
601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
602public static extern bool CalculateTransforms2(IntPtr constrain);
603
604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
606
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
608public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
609
610// =====================================================================================
611// btCollisionWorld entries
612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
613public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
614
615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
616public static extern void UpdateAabbs2(IntPtr world);
617
618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
619public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
620
621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
622public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
623
624// =====================================================================================
625// btDynamicsWorld entries
626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
627public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
628
629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
630public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
631
632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
633public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
634
635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
636public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
637// =====================================================================================
638// btCollisionObject entries
639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
640public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
641
642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
643public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
644
645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
646public static extern bool HasAnisotripicFriction2(IntPtr constrain);
647
648[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
649public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
650
651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
652public static extern float GetContactProcessingThreshold2(IntPtr obj);
653
654[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
655public static extern bool IsStaticObject2(IntPtr obj);
656
657[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
658public static extern bool IsKinematicObject2(IntPtr obj);
659
660[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
661public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
662
663[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
664public static extern bool HasContactResponse2(IntPtr obj);
665
666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
667public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
668
669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
670public static extern IntPtr GetCollisionShape2(IntPtr obj);
671
672[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
673public static extern int GetActivationState2(IntPtr obj);
674
675[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
676public static extern void SetActivationState2(IntPtr obj, int state);
677
678[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
679public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
680
681[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
682public static extern float GetDeactivationTime2(IntPtr obj);
683
684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
685public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
686
687[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
688public static extern void Activate2(IntPtr obj, bool forceActivation);
689
690[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
691public static extern bool IsActive2(IntPtr obj);
692
693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
694public static extern void SetRestitution2(IntPtr obj, float val);
695
696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
697public static extern float GetRestitution2(IntPtr obj);
698
699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
700public static extern void SetFriction2(IntPtr obj, float val);
701
702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
703public static extern float GetFriction2(IntPtr obj);
704
705 /* Haven't defined the type 'Transform'
706[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
707public static extern Transform GetWorldTransform2(IntPtr obj);
708
709[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
710public static extern void setWorldTransform2(IntPtr obj, Transform trans);
711 */
712
713[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
714public static extern Vector3 GetPosition2(IntPtr obj);
715
716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
717public static extern Quaternion GetOrientation2(IntPtr obj);
718
719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
720public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
721
722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
723public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
724
725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
726public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
727
728 /*
729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
730public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
731
732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
733public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
734 */
735
736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
737public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
738
739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
740public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
741
742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
743public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
744
745[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
746public static extern float GetHitFraction2(IntPtr obj);
747
748[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
749public static extern void SetHitFraction2(IntPtr obj, float val);
750
751[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
752public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
753
754[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
755public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
756
757[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
758public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
759
760[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
761public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
762
763[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
764public static extern float GetCcdMotionThreshold2(IntPtr obj);
765
766[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
767public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
768
769[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
770public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
771
772[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
773public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
774
775[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
776public static extern IntPtr GetUserPointer2(IntPtr obj);
777
778[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
779public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
780
781// =====================================================================================
782// btRigidBody entries
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern void ApplyGravity2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern void SetGravity2(IntPtr obj, Vector3 val);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern Vector3 GetGravity2(IntPtr obj);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern float GetLinearDamping2(IntPtr obj);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern float GetAngularDamping2(IntPtr obj);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetLinearSleepingThreshold2(IntPtr obj);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern float GetAngularSleepingThreshold2(IntPtr obj);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void ApplyDamping2(IntPtr obj, float timeStep);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
818
819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
820public static extern Vector3 GetLinearFactor2(IntPtr obj);
821
822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
823public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
824
825 /*
826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
827public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
828 */
829
830[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
831public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
832
833// Add a force to the object as if its mass is one.
834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
835public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
836
837// Set the force being applied to the object as if its mass is one.
838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
839public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
840
841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
842public static extern Vector3 GetTotalForce2(IntPtr obj);
843
844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
845public static extern Vector3 GetTotalTorque2(IntPtr obj);
846
847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
848public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
849
850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
851public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
852
853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
854public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
855
856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
857public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
858
859// Apply force at the given point. Will add torque to the object.
860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
861public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
862
863// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
865public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
866
867// Apply impulse to the object's torque. Force is scaled by object's mass.
868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
869public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
870
871// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
873public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
874
875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
876public static extern void ClearForces2(IntPtr obj);
877
878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
879public static extern void ClearAllForces2(IntPtr obj);
880
881[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
882public static extern void UpdateInertiaTensor2(IntPtr obj);
883
884[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
885public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
886
887 /*
888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
889public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
890 */
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern Vector3 GetLinearVelocity2(IntPtr obj);
894
895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
896public static extern Vector3 GetAngularVelocity2(IntPtr obj);
897
898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
899public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
900
901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
902public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
903
904[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
905public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
906
907[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
908public static extern void Translate2(IntPtr obj, Vector3 trans);
909
910[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
911public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
912
913[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
914public static extern bool WantsSleeping2(IntPtr obj);
915
916[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
917public static extern void SetAngularFactor2(IntPtr obj, float factor);
918
919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
920public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
921
922[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
923public static extern Vector3 GetAngularFactor2(IntPtr obj);
924
925[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
926public static extern bool IsInWorld2(IntPtr obj);
927
928[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
929public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
930
931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
932public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
933
934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
935public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
936
937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
938public static extern int GetNumConstraintRefs2(IntPtr obj);
939
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
942
943// =====================================================================================
944// btCollisionShape entries
945
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern float GetAngularMotionDisc2(IntPtr shape);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern bool IsPolyhedral2(IntPtr shape);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern bool IsConvex2d2(IntPtr shape);
957
958[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
959public static extern bool IsConvex2(IntPtr shape);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern bool IsNonMoving2(IntPtr shape);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern bool IsConcave2(IntPtr shape);
966
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern bool IsCompound2(IntPtr shape);
969
970[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
971public static extern bool IsSoftBody2(IntPtr shape);
972
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern bool IsInfinite2(IntPtr shape);
975
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
978
979[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
980public static extern Vector3 GetLocalScaling2(IntPtr shape);
981
982[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
983public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
984
985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
986public static extern int GetShapeType2(IntPtr shape);
987
988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
989public static extern void SetMargin2(IntPtr shape, float val);
990
991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
992public static extern float GetMargin2(IntPtr shape);
993
994// =====================================================================================
995// Debugging
996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
997public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
998
999[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1000public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1001
1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1003public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1004
1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1006public static extern void DumpAllInfo2(IntPtr sim);
1007
1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1009public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1010
1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1012public static extern void DumpPhysicsStatistics2(IntPtr sim);
1013
1014}
1015}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
new file mode 100755
index 0000000..c7a2f7e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,265 @@
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// These classes are subclassed by the various physical implementations of
37// objects. In particular, there is a version for physical instances in
38// unmanaged memory ("unman") and one for in managed memory ("XNA").
39
40// Currently, the instances of these classes are a reference to a
41// physical representation and this has no releationship to other
42// instances. Someday, refarb the usage of these classes so each instance
43// refers to a particular physical instance and this class controls reference
44// counts and such. This should be done along with adding BSShapes.
45
46public class BulletWorld
47{
48 public BulletWorld(uint worldId, BSScene bss)
49 {
50 worldID = worldId;
51 physicsScene = bss;
52 }
53 public uint worldID;
54 // The scene is only in here so very low level routines have a handle to print debug/error messages
55 public BSScene physicsScene;
56}
57
58// An allocated Bullet btRigidBody
59public class BulletBody
60{
61 public BulletBody(uint id)
62 {
63 ID = id;
64 collisionType = CollisionType.Static;
65 }
66 public uint ID;
67 public CollisionType collisionType;
68
69 public virtual void Clear() { }
70 public virtual bool HasPhysicalBody { get { return false; } }
71
72 // Apply the specificed collision mask into the physical world
73 public virtual bool ApplyCollisionMask(BSScene physicsScene)
74 {
75 // Should assert the body has been added to the physical world.
76 // (The collision masks are stored in the collision proxy cache which only exists for
77 // a collision body that is in the world.)
78 return physicsScene.PE.SetCollisionGroupMask(this,
79 BulletSimData.CollisionTypeMasks[collisionType].group,
80 BulletSimData.CollisionTypeMasks[collisionType].mask);
81 }
82
83 // Used for log messages for a unique display of the memory/object allocated to this instance
84 public virtual string AddrString
85 {
86 get { return "unknown"; }
87 }
88
89 public override string ToString()
90 {
91 StringBuilder buff = new StringBuilder();
92 buff.Append("<id=");
93 buff.Append(ID.ToString());
94 buff.Append(",p=");
95 buff.Append(AddrString);
96 buff.Append(",c=");
97 buff.Append(collisionType);
98 buff.Append(">");
99 return buff.ToString();
100 }
101}
102
103public class BulletShape
104{
105 public BulletShape()
106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public BSPhysicsShapeType type;
112 public System.UInt64 shapeKey;
113 public bool isNativeShape;
114
115 public virtual void Clear() { }
116 public virtual bool HasPhysicalShape { get { return false; } }
117
118 // Make another reference to this physical object.
119 public virtual BulletShape Clone() { return new BulletShape(); }
120
121 // Return 'true' if this and other refer to the same physical object
122 public virtual bool ReferenceSame(BulletShape xx) { return false; }
123
124 // Used for log messages for a unique display of the memory/object allocated to this instance
125 public virtual string AddrString
126 {
127 get { return "unknown"; }
128 }
129
130 public override string ToString()
131 {
132 StringBuilder buff = new StringBuilder();
133 buff.Append("<p=");
134 buff.Append(AddrString);
135 buff.Append(",s=");
136 buff.Append(type.ToString());
137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n=");
140 buff.Append(isNativeShape.ToString());
141 buff.Append(">");
142 return buff.ToString();
143 }
144}
145
146// An allocated Bullet btConstraint
147public class BulletConstraint
148{
149 public BulletConstraint()
150 {
151 }
152 public virtual void Clear() { }
153 public virtual bool HasPhysicalConstraint { get { return false; } }
154
155 // Used for log messages for a unique display of the memory/object allocated to this instance
156 public virtual string AddrString
157 {
158 get { return "unknown"; }
159 }
160}
161
162// An allocated HeightMapThing which holds various heightmap info.
163// Made a class rather than a struct so there would be only one
164// instance of this and C# will pass around pointers rather
165// than making copies.
166public class BulletHMapInfo
167{
168 public BulletHMapInfo(uint id, float[] hm) {
169 ID = id;
170 heightMap = hm;
171 terrainRegionBase = OMV.Vector3.Zero;
172 minCoords = new OMV.Vector3(100f, 100f, 25f);
173 maxCoords = new OMV.Vector3(101f, 101f, 26f);
174 minZ = maxZ = 0f;
175 sizeX = sizeY = 256f;
176 }
177 public uint ID;
178 public float[] heightMap;
179 public OMV.Vector3 terrainRegionBase;
180 public OMV.Vector3 minCoords;
181 public OMV.Vector3 maxCoords;
182 public float sizeX, sizeY;
183 public float minZ, maxZ;
184 public BulletShape terrainShape;
185 public BulletBody terrainBody;
186}
187
188// The general class of collsion object.
189public enum CollisionType
190{
191 Avatar,
192 Groundplane,
193 Terrain,
194 Static,
195 Dynamic,
196 VolumeDetect,
197 // Linkset, // A linkset should be either Static or Dynamic
198 LinksetChild,
199 Unknown
200};
201
202// Hold specification of group and mask collision flags for a CollisionType
203public struct CollisionTypeFilterGroup
204{
205 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
206 {
207 type = t;
208 group = g;
209 mask = m;
210 }
211 public CollisionType type;
212 public uint group;
213 public uint mask;
214};
215
216public static class BulletSimData
217{
218
219// Map of collisionTypes to flags for collision groups and masks.
220// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
221// but, instead, use references to this dictionary. Finding and debugging
222// collision flag problems will be made easier.
223public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
224 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
225{
226 { CollisionType.Avatar,
227 new CollisionTypeFilterGroup(CollisionType.Avatar,
228 (uint)CollisionFilterGroups.BCharacterGroup,
229 (uint)CollisionFilterGroups.BAllGroup)
230 },
231 { CollisionType.Groundplane,
232 new CollisionTypeFilterGroup(CollisionType.Groundplane,
233 (uint)CollisionFilterGroups.BGroundPlaneGroup,
234 (uint)CollisionFilterGroups.BAllGroup)
235 },
236 { CollisionType.Terrain,
237 new CollisionTypeFilterGroup(CollisionType.Terrain,
238 (uint)CollisionFilterGroups.BTerrainGroup,
239 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
240 },
241 { CollisionType.Static,
242 new CollisionTypeFilterGroup(CollisionType.Static,
243 (uint)CollisionFilterGroups.BStaticGroup,
244 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
245 },
246 { CollisionType.Dynamic,
247 new CollisionTypeFilterGroup(CollisionType.Dynamic,
248 (uint)CollisionFilterGroups.BSolidGroup,
249 (uint)(CollisionFilterGroups.BAllGroup))
250 },
251 { CollisionType.VolumeDetect,
252 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
253 (uint)CollisionFilterGroups.BSensorTrigger,
254 (uint)(~CollisionFilterGroups.BSensorTrigger))
255 },
256 { CollisionType.LinksetChild,
257 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
258 (uint)CollisionFilterGroups.BLinksetChildGroup,
259 (uint)(CollisionFilterGroups.BNoneGroup))
260 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
261 },
262};
263
264}
265}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..59cbab9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,290 @@
1CURRENT PRIORITIES
2=================================================
3Nebadon vehicles turning funny in arena
4limitMotorUp calibration (more down?)
5Vehicle angular vertical attraction
6Vehicle angular deflection
7 Preferred orientation angular correction fix
8vehicle angular banking
9Avatars walking up stairs (HALF DONE)
10 Radius of the capsule affects ability to climb edges.
11Vehicle movement on terrain smoothness
12Surfboard go wonky when turning
13 Angular motor direction is global coordinates rather than local coordinates?
14Boats float low in the water (DONE)
15Avatar movement
16 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
17 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
18 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
19Enable vehicle border crossings (at least as poorly as ODE)
20 Terrain skirts
21 Avatar created in previous region and not new region when crossing border
22 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
23Vehicle script tuning/debugging
24 Avanti speed script
25 Weapon shooter script
26Add material densities to the material types
27
28CRASHES
29=================================================
3020121129.1411: editting/moving phys object across region boundries causes crash
31 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
3220121128.1600: mesh object not rezzing (no physics mesh).
33 Causes many errors. Doesn't stop after first error with box shape.
34 Eventually crashes when deleting the object.
3520121206.1434: rez Sam-pan into OSGrid BulletSim11 region
36 Immediate simulator crash. Mono does not output any stacktrace and
37 log just stops after reporting taint-time linking of the linkset.
38
39VEHICLES TODO LIST:
40=================================================
41Border crossing with linked vehicle causes crash
42Vehicles (Move smoothly)
43Some vehicles should not be able to turn if no speed or off ground.
44Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
45Neb car jiggling left and right
46 Happens on terrain and any other mesh object. Flat cubes are much smoother.
47 This has been reduced but not eliminated.
48Implement referenceFrame for all the motion routines.
49For limitMotorUp, use raycast down to find if vehicle is in the air.
50Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
51 Verify that angular motion specified around Z moves in the vehicle coordinates.
52Verify llGetVel() is returning a smooth and good value for vehicle movement.
53llGetVel() should return the root's velocity if requested in a child prim.
54Implement function efficiency for lineaar and angular motion.
55After getting off a vehicle, the root prim is phantom (can be walked through)
56 Need to force a position update for the root prim after compound shape destruction
57Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
58Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
59 A kludge that isn't fixing the real problem of Bullet adding extra motion.
60Incorporate inter-relationship of angular corrections. For instance, angularDeflection
61 and angularMotorUp will compute same X or Y correction. When added together
62 creates over-correction and over-shoot and wabbling.
63
64GENERAL TODO LIST:
65=================================================
66Implement an avatar mesh shape. The Bullet capsule is way too limited.
67 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
68Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
69Duplicating a physical prim causes old prim to jump away
70 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
71Scenes with hundred of thousands of static objects take a lot of physics CPU time.
72BSPrim.Force should set a continious force on the prim. The force should be
73 applied each tick. Some limits?
74Gun sending shooter flying.
75Collision margin (gap between physical objects lying on each other)
76Boundry checking (crashes related to crossing boundry)
77 Add check for border edge position for avatars and objects.
78 Verify the events are created for border crossings.
79Avatar rotation (check out changes to ScenePresence for physical rotation)
80Avatar running (what does phys engine need to do?)
81Small physical objects do not interact correctly
82 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
83 The chain will fall apart and pairs will dance around on ground
84 Chains of 1x1x.2 will stay connected but will dance.
85 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
86Add PID motor for avatar movement (slow to stop, ...)
87setForce should set a constant force. Different than AddImpulse.
88Implement raycast.
89Implement ShapeCollection.Dispose()
90Implement water as a plain so raycasting and collisions can happen with same.
91Add collision penetration return
92 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
93Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
94 Also osGetPhysicsEngineVerion() maybe.
95Linkset.Position and Linkset.Orientation requre rewrite to properly return
96 child position. LinksetConstraint acts like it's at taint time!!
97Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
98Should the different PID factors have non-equal contributions for different
99 values of Efficiency?
100Selecting and deselecting physical objects causes CPU processing time to jump
101 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
102 put thousand physical objects, select and deselect same. CPU time will be large.
103Re-implement buoyancy as a separate force on the object rather than diddling gravity.
104 Register a pre-step event to add the force.
105More efficient memory usage when passing hull information from BSPrim to BulletSim
106Avatar movement motor check for zero or small movement. Somehow suppress small movements
107 when avatar has stopped and is just standing. Simple test for near zero has
108 the problem of preventing starting up (increase from zero) especially when falling.
109Physical and phantom will drop through the terrain
110
111
112LINKSETS
113======================================================
114Offset the center of the linkset to be the geometric center of all the prims
115 Not quite the same as the center-of-gravity
116Linksets should allow collisions to individual children
117 Add LocalID to children shapes in LinksetCompound and create events for individuals
118LinksetCompound: when one of the children changes orientation (like tires
119 turning on a vehicle, the whole compound object is rebuilt. Optimize this
120 so orientation/position of individual children can change without a rebuild.
121Verify/think through scripts in children of linksets. What do they reference
122 and return when getting position, velocity, ...
123Confirm constraint linksets still work after making all the changes for compound linksets.
124Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
125Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
126 For compound linksets, add ability to remove or reposition individual child shapes.
127Speed up creation of large physical linksets
128 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
129 REALLY bad for very large physical linksets (freezes the sim for many seconds).
130Eliminate collisions between objects in a linkset. (LinksetConstraint)
131 Have UserPointer point to struct with localID and linksetID?
132 Objects in original linkset still collide with each other?
133
134MORE
135======================================================
136Use the HACD convex hull routine in Bullet rather than the C# version.
137Do we need to do convex hulls all the time? Can complex meshes be left meshes?
138 There is some problem with meshes and collisions
139 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
140Debounce avatar contact so legs don't keep folding up when standing.
141Implement LSL physics controls. Like STATUS_ROTATE_X.
142Add border extensions to terrain to help region crossings and objects leaving region.
143Use a different capsule shape for avatar when sitting
144 LL uses a pyrimidal shape scaled by the avatar's bounding box
145 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
146Performance test with lots of avatars. Can BulletSim support a thousand?
147Optimize collisions in C++: only send up to the object subscribed to collisions.
148 Use collision subscription and remove the collsion(A,B) and collision(B,A)
149Check whether SimMotionState needs large if statement (see TODO).
150Implement 'top colliders' info.
151Avatar jump
152Performance measurement and changes to make quicker.
153Implement detailed physics stats (GetStats()).
154Measure performance improvement from hulls
155Test not using ghost objects for volume detect implementation.
156Performance of closures and delegates for taint processing
157 Are there faster ways?
158 Is any slowdown introduced by the existing implementation significant?
159Is there are more efficient method of implementing pre and post step actions?
160 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
161Physics Arena central pyramid: why is one side permiable?
162In SL, perfect spheres don't seem to have rolling friction. Add special case.
163Enforce physical parameter min/max:
164 Gravity: [-1, 28]
165 Friction: [0, 255]
166 Density: [1, 22587]
167 Restitution [0, 1]
168 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
169Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
170
171INTERNAL IMPROVEMENT/CLEANUP
172=================================================
173Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
174 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
175Create the physical wrapper classes (BulletBody, BulletShape) by methods on
176 BSAPITemplate and make their actual implementation Bullet engine specific.
177 For the short term, just call the existing functions in ShapeCollection.
178Consider moving prim/character body and shape destruction in destroy()
179 to postTimeTime rather than protecting all the potential sets that
180 might have been queued up.
181Remove unused fields from ShapeData (not used in API2)
182Remove unused fields from pinned memory shared parameter block
183 Create parameter variables in BSScene to replace same.
184Breakout code for mesh/hull/compound/native into separate BSShape* classes
185 Standardize access to building and reference code.
186 The skeleton classes are in the sources but are not complete or linked in.
187Make BSBody and BSShape real classes to centralize creation/changin/destruction
188 Convert state and parameter calls from BulletSimAPI direct calls to
189 calls on BSBody and BSShape
190Generalize Dynamics and PID with standardized motors.
191Generalize Linkset and vehicles into PropertyManagers
192 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
193 Potentially add events for shape destruction, etc.
194Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
195 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
196Implement linkset by setting position of children when root updated. (LinksetManual)
197 Linkset implementation using manual prim movement.
198LinkablePrim class? Would that simplify/centralize the linkset logic?
199BSScene.UpdateParameterSet() is broken. How to set params on objects?
200Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
201 bob at the water level. BSPrim.PositionSanityCheck()
202Should taints check for existance or activeness of target?
203 When destroying linksets/etc, taints can be generated for objects that are
204 actually gone when the taint happens. Crashes don't happen because the taint closure
205 keeps the object from being freed, but that is just an accident.
206 Possibly have an 'active' flag that is checked by the taint processor?
207Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
208Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
209There are TOO MANY interfaces from BulletSim core to Bullet itself
210 Think of something to eliminate one or more of the layers
211
212THREADING
213=================================================
214Do taint action immediately if not actually executing Bullet.
215 Add lock around Bullet execution and just do taint actions if simulation is not happening.
216
217DONE DONE DONE DONE
218=================================================
219Cleanup code in BSDynamics by using motors. (Resolution: started)
220Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
221 Would have better and adjustable resolution.
222Build terrain mesh so heighmap is height of the center of the square meter.
223 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
224Terrain as mesh. (Resolution: done)
225How are static linksets seen by the physics engine?
226 Resolution: they are not linked in physics. When moved, all the children are repositioned.
227Convert BSCharacter to use all API2 (Resolution: done)
228Avatar pushing difficult (too heavy?)
229Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
230Remove old code in DLL (all non-API2 stuff). (Resolution: done)
231Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
232Debug Bullet internal stats output (why is timing all wrong?)
233 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
234Implement meshes or just verify that they work. (Resolution: they do!)
235Do prim hash codes work for sculpties and meshes? (Resolution: yes)
236Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
237 Compound shapes will need the LocalID in the shapes and collision
238 processing to get it from there.
239Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
240Package Bullet source mods for Bullet internal stats output
241 (Resolution: move code into WorldData.h rather than relying on patches)
242Single prim vehicles don't seem to properly vehiclize.
243 (Resolution: mass was not getting set properly for single prim linksets)
244Add material type linkage and input all the material property definitions.
245 Skeleton classes and table are in the sources but are not filled or used.
246 (Resolution:
247Neb vehicle taking > 25ms of physics time!!
248 (Resolution: compound linksets were being rebuild WAY too often)
249Avatar height off after unsitting (floats off ground)
250 Editting appearance then moving restores.
251 Must not be initializing height when recreating capsule after unsit.
252 (Resolution: confusion of scale vs size for native objects removed)
253Light cycle falling over when driving (Resolution: implemented angularMotorUp)
254Should vehicle angular/linear movement friction happen after all the components
255 or does it only apply to the basic movement?
256 (Resolution: friction added before returning newly computed motor value.
257 What is expected by some vehicles (turning up friction to moderate speed))
258Tune terrain/object friction to be closer to SL.
259 (Resolution: added material type with friction and resolution)
260Smooth avatar movement with motor (DONE)
261 Should motor update be all at taint-time? (Yes, DONE)
262 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
263 (Resolution: added BSVMotor for avatar starting and stopping)
264llApplyImpulse()
265 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
266 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
267llSetBuoyancy() (DONE)
268 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
269Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
270 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
271Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
272 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
273Meshes rendering as bounding boxes (DONE)
274 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
275llMoveToTarget (Resolution: added simple motor to update the position.)
276Angular motor direction is global coordinates rather than local coordinates (DONE)
277Add vehicle collisions so IsColliding is properly reported. (DONE)
278 Needed for banking, limitMotorUp, movementLimiting, ...
279 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
280VehicleAddForce is not scaled by the simulation step but it is only
281 applied for one step. Should it be scaled? (DONE)
282 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
283Complete implemention of preStepActions (DONE)
284 Replace vehicle step call with prestep event.
285 Is there a need for postStepActions? postStepTaints?
286Disable activity of passive linkset children. (DONE)
287 Since the linkset is a compound object, the old prims are left lying
288 around and need to be phantomized so they don't collide, ...
289Remove HeightmapInfo from terrain specification (DONE)
290 Since C++ code does not need terrain height, this structure et al are not needed. \ No newline at end of file
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/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
index 8587a2b..8ccfda5 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
@@ -30,7 +30,7 @@ using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Reflection; 31using System.Reflection;
32using Nini.Config; 32using Nini.Config;
33using log4net; 33using log4net;
34using OpenSim.Framework; 34using OpenSim.Framework;
35 35
36namespace OpenSim.Region.Physics.Manager 36namespace OpenSim.Region.Physics.Manager
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index d24ab2a..f82b597 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -97,13 +97,20 @@ namespace OpenSim.Region.Physics.Manager
97// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 97// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98 98
99 /// <summary> 99 /// <summary>
100 /// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another. 100 /// A unique identifying string for this instance of the physics engine.
101 /// Useful in debug messages to distinguish one OdeScene instance from another.
102 /// Usually set to include the region name that the physics engine is acting for.
101 /// </summary> 103 /// </summary>
102 public string Name { get; protected set; } 104 public string Name { get; protected set; }
103 105
106 /// <summary>
107 /// A string identifying the family of this physics engine. Most common values returned
108 /// are "OpenDynamicsEngine" and "BulletSim" but others are possible.
109 /// </summary>
110 public string EngineType { get; protected set; }
111
104 // The only thing that should register for this event is the SceneGraph 112 // The only thing that should register for this event is the SceneGraph
105 // Anything else could cause problems. 113 // Anything else could cause problems.
106
107 public event physicsCrash OnPhysicsCrash; 114 public event physicsCrash OnPhysicsCrash;
108 115
109 public static PhysicsScene Null 116 public static PhysicsScene Null
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/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index 478dd95..07663b3 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -72,7 +72,7 @@ namespace OpenSim.Region.Physics.OdePlugin
72 // http://opensimulator.org/mantis/view.php?id=2750). 72 // http://opensimulator.org/mantis/view.php?id=2750).
73 d.InitODE(); 73 d.InitODE();
74 74
75 m_scene = new OdeScene(sceneIdentifier); 75 m_scene = new OdeScene(GetName(), sceneIdentifier);
76 } 76 }
77 77
78 return m_scene; 78 return m_scene;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index d53bd90..02a0b15 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -526,11 +526,12 @@ namespace OpenSim.Region.Physics.OdePlugin
526 /// These settings need to be tweaked 'exactly' right or weird stuff happens. 526 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
527 /// </summary> 527 /// </summary>
528 /// <param value="name">Name of the scene. Useful in debug messages.</param> 528 /// <param value="name">Name of the scene. Useful in debug messages.</param>
529 public OdeScene(string name) 529 public OdeScene(string engineType, string name)
530 { 530 {
531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); 531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name);
532 532
533 Name = name; 533 Name = name;
534 EngineType = engineType;
534 535
535 nearCallback = near; 536 nearCallback = near;
536 triCallback = TriCallback; 537 triCallback = TriCallback;
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/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
index e6b42e6..ed086dd 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
@@ -49,7 +49,7 @@ namespace OpenSim.Region.Physics.POSPlugin
49 49
50 public PhysicsScene GetScene(string sceneIdentifier) 50 public PhysicsScene GetScene(string sceneIdentifier)
51 { 51 {
52 return new POSScene(sceneIdentifier); 52 return new POSScene(GetName(), sceneIdentifier);
53 } 53 }
54 54
55 public string GetName() 55 public string GetName()
diff --git a/OpenSim/Region/Physics/POSPlugin/POSScene.cs b/OpenSim/Region/Physics/POSPlugin/POSScene.cs
index 2f24a50..d30d482 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSScene.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSScene.cs
@@ -43,8 +43,10 @@ namespace OpenSim.Region.Physics.POSPlugin
43 43
44 //protected internal string sceneIdentifier; 44 //protected internal string sceneIdentifier;
45 45
46 public POSScene(String _sceneIdentifier) 46 public POSScene(string engineType, String _sceneIdentifier)
47 { 47 {
48 EngineType = engineType;
49 Name = EngineType + "/" + _sceneIdentifier;
48 //sceneIdentifier = _sceneIdentifier; 50 //sceneIdentifier = _sceneIdentifier;
49 } 51 }
50 52
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/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs
index 2027ca6..d2323f5 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs
@@ -26,9 +26,11 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Threading;
29using OpenMetaverse; 30using OpenMetaverse;
30using OpenSim.Framework; 31using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes; 32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Region.ScriptEngine.Shared;
32 34
33namespace OpenSim.Region.ScriptEngine.Interfaces 35namespace OpenSim.Region.ScriptEngine.Interfaces
34{ 36{
@@ -38,11 +40,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
38 /// Initialize the API 40 /// Initialize the API
39 /// </summary> 41 /// </summary>
40 /// <remarks> 42 /// <remarks>
41 /// Each API has an identifier, which is used to load the 43 /// Each API has an identifier, which is used to load the proper runtime assembly at load time.
42 /// proper runtime assembly at load time. 44 /// <param name='scriptEngine'>/param>
43 /// <param name='engine'>/param> 45 /// <param name='host'>/param>
44 /// <param name='part'></param> 46 /// <param name='item'>/param>
45 /// <param name='item'></param> 47 /// <param name='coopSleepHandle'>/param>
46 void Initialize(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item); 48 void Initialize(
49 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle);
47 } 50 }
48} \ No newline at end of file 51} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index b04f6b6..f68612c 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -28,9 +28,11 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Threading;
31using OpenMetaverse; 32using OpenMetaverse;
32using log4net; 33using log4net;
33using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.ScriptEngine.Shared; 36using OpenSim.Region.ScriptEngine.Shared;
35using OpenSim.Region.ScriptEngine.Interfaces; 37using OpenSim.Region.ScriptEngine.Interfaces;
36 38
@@ -59,6 +61,18 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
59 public interface IScriptInstance 61 public interface IScriptInstance
60 { 62 {
61 /// <summary> 63 /// <summary>
64 /// Debug level for this script instance.
65 /// </summary>
66 /// <remarks>
67 /// Level == 0, no extra data is logged.
68 /// Level >= 1, state changes are logged.
69 /// Level >= 2, event firing is logged.
70 /// <value>
71 /// The debug level.
72 /// </value>
73 int DebugLevel { get; set; }
74
75 /// <summary>
62 /// Is the script currently running? 76 /// Is the script currently running?
63 /// </summary> 77 /// </summary>
64 bool Running { get; set; } 78 bool Running { get; set; }
@@ -93,6 +107,11 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
93 /// </summary> 107 /// </summary>
94 long MeasurementPeriodExecutionTime { get; } 108 long MeasurementPeriodExecutionTime { get; }
95 109
110 /// <summary>
111 /// Scene part in which this script instance is contained.
112 /// </summary>
113 SceneObjectPart Part { get; }
114
96 IScriptEngine Engine { get; } 115 IScriptEngine Engine { get; }
97 UUID AppDomain { get; set; } 116 UUID AppDomain { get; set; }
98 string PrimName { get; } 117 string PrimName { get; }
@@ -112,8 +131,24 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
112 131
113 uint LocalID { get; } 132 uint LocalID { get; }
114 UUID AssetID { get; } 133 UUID AssetID { get; }
134
135 /// <summary>
136 /// Inventory item containing the script used.
137 /// </summary>
138 TaskInventoryItem ScriptTask { get; }
139
115 Queue EventQueue { get; } 140 Queue EventQueue { get; }
116 141
142 /// <summary>
143 /// Number of events queued for processing.
144 /// </summary>
145 long EventsQueued { get; }
146
147 /// <summary>
148 /// Number of events processed by this script instance.
149 /// </summary>
150 long EventsProcessed { get; }
151
117 void ClearQueue(); 152 void ClearQueue();
118 int StartParam { get; set; } 153 int StartParam { get; set; }
119 154
@@ -125,7 +160,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
125 /// <summary> 160 /// <summary>
126 /// Stop the script instance. 161 /// Stop the script instance.
127 /// </summary> 162 /// </summary>
163 /// <remarks>
164 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
165 /// there is a danger that it will self-abort and not complete the reset.
166 /// </remarks>
128 /// <param name="timeout"></param> 167 /// <param name="timeout"></param>
168 /// How many milliseconds we will wait for an existing script event to finish before
169 /// forcibly aborting that event.
129 /// <returns>true if the script was successfully stopped, false otherwise</returns> 170 /// <returns>true if the script was successfully stopped, false otherwise</returns>
130 bool Stop(int timeout); 171 bool Stop(int timeout);
131 172
@@ -147,8 +188,31 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
147 object EventProcessor(); 188 object EventProcessor();
148 189
149 int EventTime(); 190 int EventTime();
150 void ResetScript(); 191
192 /// <summary>
193 /// Reset the script.
194 /// </summary>
195 /// <remarks>
196 /// This must not be called by a thread that is in the process of handling an event for this script. Otherwise
197 /// there is a danger that it will self-abort and not complete the reset. Such a thread must call
198 /// ApiResetScript() instead.
199 /// </remarks>
200 /// <param name='timeout'>
201 /// How many milliseconds we will wait for an existing script event to finish before
202 /// forcibly aborting that event prior to script reset.
203 /// </param>
204 void ResetScript(int timeout);
205
206 /// <summary>
207 /// Reset the script.
208 /// </summary>
209 /// <remarks>
210 /// This must not be called by any thread other than the one executing the scripts current event. This is
211 /// because there is no wait or abort logic if another thread is in the middle of processing a script event.
212 /// Such an external thread should use ResetScript() instead.
213 /// </remarks>
151 void ApiResetScript(); 214 void ApiResetScript();
215
152 Dictionary<string, object> GetVars(); 216 Dictionary<string, object> GetVars();
153 void SetVars(Dictionary<string, object> vars); 217 void SetVars(Dictionary<string, object> vars);
154 DetectParams GetDetectParams(int idx); 218 DetectParams GetDetectParams(int idx);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs
index b5fa6de..d03955b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Threading;
29using System.Reflection; 30using System.Reflection;
30using System.Collections; 31using System.Collections;
31using System.Collections.Generic; 32using System.Collections.Generic;
@@ -62,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
62 internal TaskInventoryItem m_item; 63 internal TaskInventoryItem m_item;
63 internal bool m_CMFunctionsEnabled = false; 64 internal bool m_CMFunctionsEnabled = false;
64 65
65 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 66 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle)
66 { 67 {
67 m_ScriptEngine = ScriptEngine; 68 m_ScriptEngine = ScriptEngine;
68 m_host = host; 69 m_host = host;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 525e575..da2a90f 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -87,10 +87,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
87 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi 87 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
88 { 88 {
89 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 89 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
90
90 protected IScriptEngine m_ScriptEngine; 91 protected IScriptEngine m_ScriptEngine;
91 protected SceneObjectPart m_host; 92 protected SceneObjectPart m_host;
92 93
93 /// <summary> 94 /// <summary>
95 /// Used for script sleeps when we are using co-operative script termination.
96 /// </summary>
97 /// <remarks>null if co-operative script termination is not active</remarks>
98 EventWaitHandle m_coopSleepHandle;
99
100 /// <summary>
94 /// The item that hosts this script 101 /// The item that hosts this script
95 /// </summary> 102 /// </summary>
96 protected TaskInventoryItem m_item; 103 protected TaskInventoryItem m_item;
@@ -100,6 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
100 protected float m_ScriptDelayFactor = 1.0f; 107 protected float m_ScriptDelayFactor = 1.0f;
101 protected float m_ScriptDistanceFactor = 1.0f; 108 protected float m_ScriptDistanceFactor = 1.0f;
102 protected float m_MinTimerInterval = 0.5f; 109 protected float m_MinTimerInterval = 0.5f;
110 protected float m_recoilScaleFactor = 0.0f;
103 111
104 protected DateTime m_timer = DateTime.Now; 112 protected DateTime m_timer = DateTime.Now;
105 protected bool m_waitingForScriptAnswer = false; 113 protected bool m_waitingForScriptAnswer = false;
@@ -141,33 +149,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
141 {"TURNRIGHT", "Turning Right"} 149 {"TURNRIGHT", "Turning Right"}
142 }; 150 };
143 151
144 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 152 public void Initialize(
153 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle)
145 { 154 {
146/*
147 m_ShoutSayTimer = new Timer(1000);
148 m_ShoutSayTimer.Elapsed += SayShoutTimerElapsed;
149 m_ShoutSayTimer.AutoReset = true;
150 m_ShoutSayTimer.Start();
151*/
152 m_lastSayShoutCheck = DateTime.UtcNow; 155 m_lastSayShoutCheck = DateTime.UtcNow;
153 156
154 m_ScriptEngine = ScriptEngine; 157 m_ScriptEngine = scriptEngine;
155 m_host = host; 158 m_host = host;
156 m_item = item; 159 m_item = item;
157 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); 160 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
161 m_coopSleepHandle = coopSleepHandle;
158 162
159 LoadLimits(); // read script limits from config. 163 LoadConfig();
160 164
161 m_TransferModule = 165 m_TransferModule =
162 m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>(); 166 m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
163 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>(); 167 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
164 m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>(); 168 m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
165 169
166 AsyncCommands = new AsyncCommandManager(ScriptEngine); 170 AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
167 } 171 }
168 172
169 /* load configuration items that affect script, object and run-time behavior. */ 173 /// <summary>
170 private void LoadLimits() 174 /// Load configuration items that affect script, object and run-time behavior. */
175 /// </summary>
176 private void LoadConfig()
171 { 177 {
172 m_ScriptDelayFactor = 178 m_ScriptDelayFactor =
173 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); 179 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
@@ -181,12 +187,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
181 m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); 187 m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255);
182 if (m_notecardLineReadCharsMax > 65535) 188 if (m_notecardLineReadCharsMax > 65535)
183 m_notecardLineReadCharsMax = 65535; 189 m_notecardLineReadCharsMax = 65535;
190
184 // load limits for particular subsystems. 191 // load limits for particular subsystems.
185 IConfig SMTPConfig; 192 IConfig SMTPConfig;
186 if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { 193 if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) {
187 // there's an smtp config, so load in the snooze time. 194 // there's an smtp config, so load in the snooze time.
188 EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); 195 EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
189 } 196 }
197
198 // Rezzing an object with a velocity can create recoil. This feature seems to have been
199 // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
200 // it by this factor. May be zero to turn off recoil all together.
201 m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
190 } 202 }
191 203
192 public override Object InitializeLifetimeService() 204 public override Object InitializeLifetimeService()
@@ -207,7 +219,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
207 delay = (int)((float)delay * m_ScriptDelayFactor); 219 delay = (int)((float)delay * m_ScriptDelayFactor);
208 if (delay == 0) 220 if (delay == 0)
209 return; 221 return;
210 System.Threading.Thread.Sleep(delay); 222
223 Sleep(delay);
224 }
225
226 protected virtual void Sleep(int delay)
227 {
228 if (m_coopSleepHandle == null)
229 System.Threading.Thread.Sleep(delay);
230 else if (m_coopSleepHandle.WaitOne(delay))
231 throw new ScriptCoopStopException();
211 } 232 }
212 233
213 public Scene World 234 public Scene World
@@ -1483,19 +1504,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1483 return 0; 1504 return 0;
1484 1505
1485 case ScriptBaseClass.STATUS_ROTATE_X: 1506 case ScriptBaseClass.STATUS_ROTATE_X:
1486 if (m_host.GetAxisRotation(2) == 2) 1507 // if (m_host.GetAxisRotation(2) != 0)
1508 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
1487 return 1; 1509 return 1;
1488 else 1510 else
1489 return 0; 1511 return 0;
1490 1512
1491 case ScriptBaseClass.STATUS_ROTATE_Y: 1513 case ScriptBaseClass.STATUS_ROTATE_Y:
1492 if (m_host.GetAxisRotation(4) == 4) 1514 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
1493 return 1; 1515 return 1;
1494 else 1516 else
1495 return 0; 1517 return 0;
1496 1518
1497 case ScriptBaseClass.STATUS_ROTATE_Z: 1519 case ScriptBaseClass.STATUS_ROTATE_Z:
1498 if (m_host.GetAxisRotation(8) == 8) 1520 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
1499 return 1; 1521 return 1;
1500 else 1522 else
1501 return 0; 1523 return 0;
@@ -3140,11 +3162,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3140 3162
3141 PhysicsActor pa = new_group.RootPart.PhysActor; 3163 PhysicsActor pa = new_group.RootPart.PhysActor;
3142 3164
3165 //Recoil.
3143 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) 3166 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
3144 { 3167 {
3145 float groupmass = new_group.GetMass(); 3168 float groupmass = new_group.GetMass();
3146 vel *= -groupmass; 3169 Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
3147 llApplyImpulse(vel, 0); 3170 if (recoil != Vector3.Zero)
3171 {
3172 llApplyImpulse(recoil, 0);
3173 }
3148 } 3174 }
3149 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) 3175 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
3150 return; 3176 return;
@@ -3219,7 +3245,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3219 { 3245 {
3220// m_log.Info("llSleep snoozing " + sec + "s."); 3246// m_log.Info("llSleep snoozing " + sec + "s.");
3221 m_host.AddScriptLPS(1); 3247 m_host.AddScriptLPS(1);
3222 Thread.Sleep((int)(sec * 1000)); 3248
3249 Sleep((int)(sec * 1000));
3223 } 3250 }
3224 3251
3225 public LSL_Float llGetMass() 3252 public LSL_Float llGetMass()
@@ -3321,7 +3348,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3321 /// <summary> 3348 /// <summary>
3322 /// Attach the object containing this script to the avatar that owns it. 3349 /// Attach the object containing this script to the avatar that owns it.
3323 /// </summary> 3350 /// </summary>
3324 /// <param name='attachment'>The attachment point (e.g. ATTACH_CHEST)</param> 3351 /// <param name='attachmentPoint'>
3352 /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
3353 /// </param>
3325 /// <returns>true if the attach suceeded, false if it did not</returns> 3354 /// <returns>true if the attach suceeded, false if it did not</returns>
3326 public bool AttachToAvatar(int attachmentPoint) 3355 public bool AttachToAvatar(int attachmentPoint)
3327 { 3356 {
@@ -3752,21 +3781,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3752 } 3781 }
3753 else 3782 else
3754 { 3783 {
3755 bool sitting = false; 3784 if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID))
3756 if (m_host.SitTargetAvatar == agentID)
3757 {
3758 sitting = true;
3759 }
3760 else
3761 {
3762 foreach (SceneObjectPart p in m_host.ParentGroup.Parts)
3763 {
3764 if (p.SitTargetAvatar == agentID)
3765 sitting = true;
3766 }
3767 }
3768
3769 if (sitting)
3770 { 3785 {
3771 // When agent is sitting, certain permissions are implicit if requested from sitting agent 3786 // When agent is sitting, certain permissions are implicit if requested from sitting agent
3772 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | 3787 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
@@ -3808,7 +3823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3808 INPCModule npcModule = World.RequestModuleInterface<INPCModule>(); 3823 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
3809 if (npcModule != null && npcModule.IsNPC(agentID, World)) 3824 if (npcModule != null && npcModule.IsNPC(agentID, World))
3810 { 3825 {
3811 if (agentID == m_host.ParentGroup.OwnerID || npcModule.GetOwner(agentID) == m_host.ParentGroup.OwnerID) 3826 if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
3812 { 3827 {
3813 lock (m_host.TaskInventory) 3828 lock (m_host.TaskInventory)
3814 { 3829 {
@@ -4183,62 +4198,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4183 public LSL_String llGetLinkName(int linknum) 4198 public LSL_String llGetLinkName(int linknum)
4184 { 4199 {
4185 m_host.AddScriptLPS(1); 4200 m_host.AddScriptLPS(1);
4186 // simplest case, this prims link number
4187 if (linknum == m_host.LinkNum || linknum == ScriptBaseClass.LINK_THIS)
4188 return m_host.Name;
4189 4201
4190 // parse for sitting avatare-names 4202 if (linknum < 0)
4191 List<String> nametable = new List<String>();
4192 World.ForEachRootScenePresence(delegate(ScenePresence presence)
4193 { 4203 {
4194 SceneObjectPart sitPart = presence.ParentPart; 4204 if (linknum == ScriptBaseClass.LINK_THIS)
4195 if (sitPart != null && m_host.ParentGroup.ContainsPart(sitPart.LocalId))
4196 nametable.Add(presence.ControllingClient.Name);
4197 });
4198
4199 int totalprims = m_host.ParentGroup.PrimCount + nametable.Count;
4200 if (totalprims > m_host.ParentGroup.PrimCount)
4201 {
4202 // sitting Avatar-Name with negativ linknum / SinglePrim
4203 if (linknum < 0 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
4204 return nametable[0];
4205 // Prim-Name / SinglePrim Sitting Avatar
4206 if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1)
4207 return m_host.Name; 4205 return m_host.Name;
4208 // LinkNumber > of Real PrimSet = AvatarName 4206 else
4209 if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims) 4207 return ScriptBaseClass.NULL_KEY;
4210 return nametable[totalprims - linknum];
4211 } 4208 }
4212 4209
4213 // Single prim 4210 int actualPrimCount = m_host.ParentGroup.PrimCount;
4214 if (m_host.LinkNum == 0) 4211 List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
4212 int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
4213
4214 // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
4215 // prim that has any avatars sat upon it (in which case the root prim is link 1).
4216 if (linknum == 0)
4215 { 4217 {
4216 if (linknum == 0 || linknum == ScriptBaseClass.LINK_ROOT) 4218 if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
4217 return m_host.Name; 4219 return m_host.Name;
4218 else
4219 return UUID.Zero.ToString();
4220 }
4221 4220
4222 // Link set 4221 return ScriptBaseClass.NULL_KEY;
4223 SceneObjectPart part = null; 4222 }
4224 if (m_host.LinkNum == 1) // this is the Root prim 4223 // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
4224 // here we must match 1 (ScriptBaseClass.LINK_ROOT).
4225 else if (linknum == 1 && actualPrimCount == 1)
4225 { 4226 {
4226 if (linknum < 0) 4227 if (sittingAvatarIds.Count > 0)
4227 part = m_host.ParentGroup.GetLinkNumPart(2); 4228 return m_host.ParentGroup.RootPart.Name;
4228 else 4229 else
4229 part = m_host.ParentGroup.GetLinkNumPart(linknum); 4230 return ScriptBaseClass.NULL_KEY;
4230 } 4231 }
4231 else // this is a child prim 4232 else if (linknum <= adjustedPrimCount)
4232 { 4233 {
4233 if (linknum < 2) 4234 if (linknum <= actualPrimCount)
4234 part = m_host.ParentGroup.GetLinkNumPart(1); 4235 {
4236 return m_host.ParentGroup.GetLinkNumPart(linknum).Name;
4237 }
4235 else 4238 else
4236 part = m_host.ParentGroup.GetLinkNumPart(linknum); 4239 {
4240 ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
4241 if (sp != null)
4242 return sp.Name;
4243 else
4244 return ScriptBaseClass.NULL_KEY;
4245 }
4237 } 4246 }
4238 if (part != null)
4239 return part.Name;
4240 else 4247 else
4241 return UUID.Zero.ToString(); 4248 {
4249 return ScriptBaseClass.NULL_KEY;
4250 }
4242 } 4251 }
4243 4252
4244 public LSL_Integer llGetInventoryNumber(int type) 4253 public LSL_Integer llGetInventoryNumber(int type)
@@ -5851,9 +5860,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5851 } 5860 }
5852 5861
5853 /// <summary> 5862 /// <summary>
5854 /// Insert the list identified by <src> into the 5863 /// Insert the list identified by <paramref name="src"/> into the
5855 /// list designated by <dest> such that the first 5864 /// list designated by <paramref name="dest"/> such that the first
5856 /// new element has the index specified by <index> 5865 /// new element has the index specified by <paramref name="index"/>
5857 /// </summary> 5866 /// </summary>
5858 5867
5859 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index) 5868 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
@@ -6686,6 +6695,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6686 ps.BurstSpeedMax = 1.0f; 6695 ps.BurstSpeedMax = 1.0f;
6687 ps.BurstRate = 0.1f; 6696 ps.BurstRate = 0.1f;
6688 ps.PartMaxAge = 10.0f; 6697 ps.PartMaxAge = 10.0f;
6698 ps.BurstPartCount = 1;
6689 return ps; 6699 return ps;
6690 } 6700 }
6691 6701
@@ -6707,10 +6717,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6707 SetParticleSystem(m_host, rules); 6717 SetParticleSystem(m_host, rules);
6708 } 6718 }
6709 6719
6710 private void SetParticleSystem(SceneObjectPart part, LSL_List rules) 6720 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6711 { 6721 {
6712
6713
6714 if (rules.Length == 0) 6722 if (rules.Length == 0)
6715 { 6723 {
6716 part.RemoveParticleSystem(); 6724 part.RemoveParticleSystem();
@@ -7367,6 +7375,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7367 public void llCloseRemoteDataChannel(string channel) 7375 public void llCloseRemoteDataChannel(string channel)
7368 { 7376 {
7369 m_host.AddScriptLPS(1); 7377 m_host.AddScriptLPS(1);
7378
7379 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
7380 if (xmlRpcRouter != null)
7381 {
7382 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
7383 }
7384
7370 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 7385 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7371 xmlrpcMod.CloseXMLRPCChannel((UUID)channel); 7386 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
7372 ScriptSleep(1000); 7387 ScriptSleep(1000);
@@ -13255,7 +13270,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13255 /// Get a notecard line. 13270 /// Get a notecard line.
13256 /// </summary> 13271 /// </summary>
13257 /// <param name="assetID"></param> 13272 /// <param name="assetID"></param>
13258 /// <param name="line">Lines start at index 0</param> 13273 /// <param name="lineNumber">Lines start at index 0</param>
13259 /// <returns></returns> 13274 /// <returns></returns>
13260 public static string GetLine(UUID assetID, int lineNumber) 13275 public static string GetLine(UUID assetID, int lineNumber)
13261 { 13276 {
@@ -13284,9 +13299,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13284 /// Get a notecard line. 13299 /// Get a notecard line.
13285 /// </summary> 13300 /// </summary>
13286 /// <param name="assetID"></param> 13301 /// <param name="assetID"></param>
13287 /// <param name="line">Lines start at index 0</param> 13302 /// <param name="lineNumber">Lines start at index 0</param>
13288 /// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para> 13303 /// <param name="maxLength">
13289 /// <returns></returns> 13304 /// Maximum length of the returned line.
13305 /// </param>
13306 /// <returns>
13307 /// If the line length is longer than <paramref name="maxLength"/>,
13308 /// the return string will be truncated.
13309 /// </returns>
13290 public static string GetLine(UUID assetID, int lineNumber, int maxLength) 13310 public static string GetLine(UUID assetID, int lineNumber, int maxLength)
13291 { 13311 {
13292 string line = GetLine(assetID, lineNumber); 13312 string line = GetLine(assetID, lineNumber);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
index ceb4660..a08ccc8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs
@@ -30,6 +30,7 @@ using System.Reflection;
30using System.Collections; 30using System.Collections;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
33using System.Threading;
33using OpenMetaverse; 34using OpenMetaverse;
34using Nini.Config; 35using Nini.Config;
35using OpenSim; 36using OpenSim;
@@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
61 internal bool m_LSFunctionsEnabled = false; 62 internal bool m_LSFunctionsEnabled = false;
62 internal IScriptModuleComms m_comms = null; 63 internal IScriptModuleComms m_comms = null;
63 64
64 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 65 public void Initialize(
66 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle)
65 { 67 {
66 m_ScriptEngine = ScriptEngine; 68 m_ScriptEngine = scriptEngine;
67 m_host = host; 69 m_host = host;
68 70
69 if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) 71 if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false))
@@ -92,10 +94,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
92 get { return m_ScriptEngine.World; } 94 get { return m_ScriptEngine.World; }
93 } 95 }
94 96
95 // 97 /// <summary>
96 //Dumps an error message on the debug console. 98 /// Dumps an error message on the debug console.
97 // 99 /// </summary>
98
99 internal void LSShoutError(string message) 100 internal void LSShoutError(string message)
100 { 101 {
101 if (message.Length > 1023) 102 if (message.Length > 1023)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
index 8f34833..981499e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -30,6 +30,7 @@ using System.Reflection;
30using System.Collections; 30using System.Collections;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
33using System.Threading;
33using OpenMetaverse; 34using OpenMetaverse;
34using Nini.Config; 35using Nini.Config;
35using OpenSim; 36using OpenSim;
@@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
61 internal bool m_MODFunctionsEnabled = false; 62 internal bool m_MODFunctionsEnabled = false;
62 internal IScriptModuleComms m_comms = null; 63 internal IScriptModuleComms m_comms = null;
63 64
64 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 65 public void Initialize(
66 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle)
65 { 67 {
66 m_ScriptEngine = ScriptEngine; 68 m_ScriptEngine = scriptEngine;
67 m_host = host; 69 m_host = host;
68 m_item = item; 70 m_item = item;
69 71
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 51c8c7e..49857cf 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -143,9 +143,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
143 143
144 protected IUrlModule m_UrlModule = null; 144 protected IUrlModule m_UrlModule = null;
145 145
146 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) 146 public void Initialize(
147 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, EventWaitHandle coopSleepHandle)
147 { 148 {
148 m_ScriptEngine = ScriptEngine; 149 m_ScriptEngine = scriptEngine;
149 m_host = host; 150 m_host = host;
150 m_item = item; 151 m_item = item;
151 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); 152 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
@@ -254,11 +255,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
254 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); 255 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message);
255 } 256 }
256 257
258 // Returns of the function is allowed. Throws a script exception if not allowed.
257 public void CheckThreatLevel(ThreatLevel level, string function) 259 public void CheckThreatLevel(ThreatLevel level, string function)
258 { 260 {
259 if (!m_OSFunctionsEnabled) 261 if (!m_OSFunctionsEnabled)
260 OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws 262 OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws
261 263
264 string reasonWhyNot = CheckThreatLevelTest(level, function);
265 if (!String.IsNullOrEmpty(reasonWhyNot))
266 {
267 OSSLError(reasonWhyNot);
268 }
269 }
270
271 // Check to see if function is allowed. Returns an empty string if function permitted
272 // or a string explaining why this function can't be used.
273 private string CheckThreatLevelTest(ThreatLevel level, string function)
274 {
262 if (!m_FunctionPerms.ContainsKey(function)) 275 if (!m_FunctionPerms.ContainsKey(function))
263 { 276 {
264 FunctionPerms perms = new FunctionPerms(); 277 FunctionPerms perms = new FunctionPerms();
@@ -338,10 +351,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
338 { 351 {
339 // Allow / disallow by threat level 352 // Allow / disallow by threat level
340 if (level > m_MaxThreatLevel) 353 if (level > m_MaxThreatLevel)
341 OSSLError( 354 return
342 String.Format( 355 String.Format(
343 "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", 356 "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.",
344 function, m_MaxThreatLevel, level)); 357 function, m_MaxThreatLevel, level);
345 } 358 }
346 else 359 else
347 { 360 {
@@ -351,7 +364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
351 if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID)) 364 if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID))
352 { 365 {
353 // prim owner is in the list of allowed owners 366 // prim owner is in the list of allowed owners
354 return; 367 return String.Empty;
355 } 368 }
356 369
357 UUID ownerID = m_item.OwnerID; 370 UUID ownerID = m_item.OwnerID;
@@ -363,7 +376,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
363 376
364 if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) 377 if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero)
365 { 378 {
366 return; 379 return String.Empty;
367 } 380 }
368 } 381 }
369 382
@@ -374,7 +387,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
374 387
375 if (land.LandData.OwnerID == ownerID) 388 if (land.LandData.OwnerID == ownerID)
376 { 389 {
377 return; 390 return String.Empty;
378 } 391 }
379 } 392 }
380 393
@@ -384,7 +397,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
384 //Only Estate Managers may use the function 397 //Only Estate Managers may use the function
385 if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) 398 if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID)
386 { 399 {
387 return; 400 return String.Empty;
388 } 401 }
389 } 402 }
390 403
@@ -393,25 +406,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
393 { 406 {
394 if (World.RegionInfo.EstateSettings.EstateOwner == ownerID) 407 if (World.RegionInfo.EstateSettings.EstateOwner == ownerID)
395 { 408 {
396 return; 409 return String.Empty;
397 } 410 }
398 } 411 }
399 412
400 if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) 413 if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID))
401 OSSLError( 414 return(
402 String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", 415 String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.",
403 function)); 416 function));
404 417
405 if (m_item.CreatorID != ownerID) 418 if (m_item.CreatorID != ownerID)
406 { 419 {
407 if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) 420 if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0)
408 OSSLError( 421 return String.Format("{0} permission denied. Script permissions error.", function);
409 String.Format("{0} permission denied. Script permissions error.",
410 function));
411 422
412 } 423 }
413 } 424 }
414 } 425 }
426 return String.Empty;
415 } 427 }
416 428
417 internal void OSSLDeprecated(string function, string replacement) 429 internal void OSSLDeprecated(string function, string replacement)
@@ -1214,12 +1226,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1214 sunHour += 24.0; 1226 sunHour += 24.0;
1215 1227
1216 World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; 1228 World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun;
1217 World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 1229 World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30
1218 World.RegionInfo.RegionSettings.FixedSun = sunFixed; 1230 World.RegionInfo.RegionSettings.FixedSun = sunFixed;
1219 World.RegionInfo.RegionSettings.Save(); 1231 World.RegionInfo.RegionSettings.Save();
1220 1232
1221 World.EventManager.TriggerEstateToolsSunUpdate( 1233 World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle);
1222 World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour);
1223 } 1234 }
1224 1235
1225 /// <summary> 1236 /// <summary>
@@ -1244,8 +1255,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1244 World.RegionInfo.EstateSettings.FixedSun = sunFixed; 1255 World.RegionInfo.EstateSettings.FixedSun = sunFixed;
1245 World.RegionInfo.EstateSettings.Save(); 1256 World.RegionInfo.EstateSettings.Save();
1246 1257
1247 World.EventManager.TriggerEstateToolsSunUpdate( 1258 World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle);
1248 World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour);
1249 } 1259 }
1250 1260
1251 /// <summary> 1261 /// <summary>
@@ -1569,6 +1579,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1569 } 1579 }
1570 } 1580 }
1571 1581
1582 public string osGetPhysicsEngineType()
1583 {
1584 // High because it can be used to target attacks to known weaknesses
1585 // This would allow a new class of griefer scripts that don't even
1586 // require their user to know what they are doing (see script
1587 // kiddie)
1588 // Because it would be nice if scripts didn't blow up if the information
1589 // about the physics engine, this function returns an empty string if
1590 // the user does not have permission to see it. This as opposed to
1591 // throwing an exception.
1592 m_host.AddScriptLPS(1);
1593 string ret = String.Empty;
1594 if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType")))
1595 {
1596 if (m_ScriptEngine.World.PhysicsScene != null)
1597 {
1598 ret = m_ScriptEngine.World.PhysicsScene.EngineType;
1599 // An old physics engine might have an uninitialized engine type
1600 if (ret == null)
1601 ret = "unknown";
1602 }
1603 }
1604
1605 return ret;
1606 }
1607
1572 public string osGetSimulatorVersion() 1608 public string osGetSimulatorVersion()
1573 { 1609 {
1574 // High because it can be used to target attacks to known weaknesses 1610 // High because it can be used to target attacks to known weaknesses
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 4dd795d..d3ef378 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -42,6 +42,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
42 { 42 {
43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 44
45 /// <summary>
46 /// Used by one-off and repeated sensors
47 /// </summary>
48 public class SensorInfo
49 {
50 public uint localID;
51 public UUID itemID;
52 public double interval;
53 public DateTime next;
54
55 public string name;
56 public UUID keyID;
57 public int type;
58 public double range;
59 public double arc;
60 public SceneObjectPart host;
61
62 public SensorInfo Clone()
63 {
64 return (SensorInfo)this.MemberwiseClone();
65 }
66 }
67
45 public AsyncCommandManager m_CmdManager; 68 public AsyncCommandManager m_CmdManager;
46 69
47 /// <summary> 70 /// <summary>
@@ -78,24 +101,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
78 private int maximumToReturn = 16; 101 private int maximumToReturn = 16;
79 102
80 // 103 //
81 // SenseRepeater and Sensors
82 //
83 private class SenseRepeatClass
84 {
85 public uint localID;
86 public UUID itemID;
87 public double interval;
88 public DateTime next;
89
90 public string name;
91 public UUID keyID;
92 public int type;
93 public double range;
94 public double arc;
95 public SceneObjectPart host;
96 }
97
98 //
99 // Sensed entity 104 // Sensed entity
100 // 105 //
101 private class SensedEntity : IComparable 106 private class SensedEntity : IComparable
@@ -127,7 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
127 /// 132 ///
128 /// Always lock SenseRepeatListLock when updating this list. 133 /// Always lock SenseRepeatListLock when updating this list.
129 /// </remarks> 134 /// </remarks>
130 private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>(); 135 private List<SensorInfo> SenseRepeaters = new List<SensorInfo>();
131 private object SenseRepeatListLock = new object(); 136 private object SenseRepeatListLock = new object();
132 137
133 public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID, 138 public void SetSenseRepeatEvent(uint m_localID, UUID m_itemID,
@@ -141,7 +146,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
141 return; 146 return;
142 147
143 // Add to timer 148 // Add to timer
144 SenseRepeatClass ts = new SenseRepeatClass(); 149 SensorInfo ts = new SensorInfo();
145 ts.localID = m_localID; 150 ts.localID = m_localID;
146 ts.itemID = m_itemID; 151 ts.itemID = m_itemID;
147 ts.interval = sec; 152 ts.interval = sec;
@@ -160,11 +165,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
160 AddSenseRepeater(ts); 165 AddSenseRepeater(ts);
161 } 166 }
162 167
163 private void AddSenseRepeater(SenseRepeatClass senseRepeater) 168 private void AddSenseRepeater(SensorInfo senseRepeater)
164 { 169 {
165 lock (SenseRepeatListLock) 170 lock (SenseRepeatListLock)
166 { 171 {
167 List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(SenseRepeaters); 172 List<SensorInfo> newSenseRepeaters = new List<SensorInfo>(SenseRepeaters);
168 newSenseRepeaters.Add(senseRepeater); 173 newSenseRepeaters.Add(senseRepeater);
169 SenseRepeaters = newSenseRepeaters; 174 SenseRepeaters = newSenseRepeaters;
170 } 175 }
@@ -175,8 +180,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
175 // Remove from timer 180 // Remove from timer
176 lock (SenseRepeatListLock) 181 lock (SenseRepeatListLock)
177 { 182 {
178 List<SenseRepeatClass> newSenseRepeaters = new List<SenseRepeatClass>(); 183 List<SensorInfo> newSenseRepeaters = new List<SensorInfo>();
179 foreach (SenseRepeatClass ts in SenseRepeaters) 184 foreach (SensorInfo ts in SenseRepeaters)
180 { 185 {
181 if (ts.localID != m_localID || ts.itemID != m_itemID) 186 if (ts.localID != m_localID || ts.itemID != m_itemID)
182 { 187 {
@@ -191,7 +196,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
191 public void CheckSenseRepeaterEvents() 196 public void CheckSenseRepeaterEvents()
192 { 197 {
193 // Go through all timers 198 // Go through all timers
194 foreach (SenseRepeatClass ts in SenseRepeaters) 199 foreach (SensorInfo ts in SenseRepeaters)
195 { 200 {
196 // Time has passed? 201 // Time has passed?
197 if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) 202 if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
@@ -208,7 +213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
208 double range, double arc, SceneObjectPart host) 213 double range, double arc, SceneObjectPart host)
209 { 214 {
210 // Add to timer 215 // Add to timer
211 SenseRepeatClass ts = new SenseRepeatClass(); 216 SensorInfo ts = new SensorInfo();
212 ts.localID = m_localID; 217 ts.localID = m_localID;
213 ts.itemID = m_itemID; 218 ts.itemID = m_itemID;
214 ts.interval = 0; 219 ts.interval = 0;
@@ -224,7 +229,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
224 SensorSweep(ts); 229 SensorSweep(ts);
225 } 230 }
226 231
227 private void SensorSweep(SenseRepeatClass ts) 232 private void SensorSweep(SensorInfo ts)
228 { 233 {
229 if (ts.host == null) 234 if (ts.host == null)
230 { 235 {
@@ -300,7 +305,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
300 } 305 }
301 } 306 }
302 307
303 private List<SensedEntity> doObjectSensor(SenseRepeatClass ts) 308 private List<SensedEntity> doObjectSensor(SensorInfo ts)
304 { 309 {
305 List<EntityBase> Entities; 310 List<EntityBase> Entities;
306 List<SensedEntity> sensedEntities = new List<SensedEntity>(); 311 List<SensedEntity> sensedEntities = new List<SensedEntity>();
@@ -451,7 +456,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
451 return sensedEntities; 456 return sensedEntities;
452 } 457 }
453 458
454 private List<SensedEntity> doAgentSensor(SenseRepeatClass ts) 459 private List<SensedEntity> doAgentSensor(SensorInfo ts)
455 { 460 {
456 List<SensedEntity> sensedEntities = new List<SensedEntity>(); 461 List<SensedEntity> sensedEntities = new List<SensedEntity>();
457 462
@@ -630,7 +635,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
630 { 635 {
631 List<Object> data = new List<Object>(); 636 List<Object> data = new List<Object>();
632 637
633 foreach (SenseRepeatClass ts in SenseRepeaters) 638 foreach (SensorInfo ts in SenseRepeaters)
634 { 639 {
635 if (ts.itemID == itemID) 640 if (ts.itemID == itemID)
636 { 641 {
@@ -660,7 +665,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
660 665
661 while (idx < data.Length) 666 while (idx < data.Length)
662 { 667 {
663 SenseRepeatClass ts = new SenseRepeatClass(); 668 SensorInfo ts = new SensorInfo();
664 669
665 ts.localID = localID; 670 ts.localID = localID;
666 ts.itemID = itemID; 671 ts.itemID = itemID;
@@ -681,5 +686,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
681 idx += 6; 686 idx += 6;
682 } 687 }
683 } 688 }
689
690 public List<SensorInfo> GetSensorInfo()
691 {
692 List<SensorInfo> retList = new List<SensorInfo>();
693
694 lock (SenseRepeatListLock)
695 {
696 foreach (SensorInfo i in SenseRepeaters)
697 retList.Add(i.Clone());
698 }
699
700 return retList;
701 }
684 } 702 }
685} 703} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
index 9ee6946..68aacd2 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
@@ -35,6 +35,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
35{ 35{
36 public class Timer 36 public class Timer
37 { 37 {
38 public class TimerInfo
39 {
40 public uint localID;
41 public UUID itemID;
42 //public double interval;
43 public long interval;
44 //public DateTime next;
45 public long next;
46
47 public TimerInfo Clone()
48 {
49 return (TimerInfo)this.MemberwiseClone();
50 }
51 }
52
38 public AsyncCommandManager m_CmdManager; 53 public AsyncCommandManager m_CmdManager;
39 54
40 public int TimersCount 55 public int TimersCount
@@ -59,17 +74,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
59 return localID.ToString() + itemID.ToString(); 74 return localID.ToString() + itemID.ToString();
60 } 75 }
61 76
62 private class TimerClass 77 private Dictionary<string,TimerInfo> Timers = new Dictionary<string,TimerInfo>();
63 {
64 public uint localID;
65 public UUID itemID;
66 //public double interval;
67 public long interval;
68 //public DateTime next;
69 public long next;
70 }
71
72 private Dictionary<string,TimerClass> Timers = new Dictionary<string,TimerClass>();
73 private object TimerListLock = new object(); 78 private object TimerListLock = new object();
74 79
75 public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec) 80 public void SetTimerEvent(uint m_localID, UUID m_itemID, double sec)
@@ -81,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
81 } 86 }
82 87
83 // Add to timer 88 // Add to timer
84 TimerClass ts = new TimerClass(); 89 TimerInfo ts = new TimerInfo();
85 ts.localID = m_localID; 90 ts.localID = m_localID;
86 ts.itemID = m_itemID; 91 ts.itemID = m_itemID;
87 ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait 92 ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait
@@ -118,14 +123,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
118 if (Timers.Count == 0) 123 if (Timers.Count == 0)
119 return; 124 return;
120 125
121 Dictionary<string, TimerClass>.ValueCollection tvals; 126 Dictionary<string, TimerInfo>.ValueCollection tvals;
122 lock (TimerListLock) 127 lock (TimerListLock)
123 { 128 {
124 // Go through all timers 129 // Go through all timers
125 tvals = Timers.Values; 130 tvals = Timers.Values;
126 } 131 }
127 132
128 foreach (TimerClass ts in tvals) 133 foreach (TimerInfo ts in tvals)
129 { 134 {
130 // Time has passed? 135 // Time has passed?
131 if (ts.next < DateTime.Now.Ticks) 136 if (ts.next < DateTime.Now.Ticks)
@@ -149,8 +154,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
149 154
150 lock (TimerListLock) 155 lock (TimerListLock)
151 { 156 {
152 Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values; 157 Dictionary<string, TimerInfo>.ValueCollection tvals = Timers.Values;
153 foreach (TimerClass ts in tvals) 158 foreach (TimerInfo ts in tvals)
154 { 159 {
155 if (ts.itemID == itemID) 160 if (ts.itemID == itemID)
156 { 161 {
@@ -169,7 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
169 174
170 while (idx < data.Length) 175 while (idx < data.Length)
171 { 176 {
172 TimerClass ts = new TimerClass(); 177 TimerInfo ts = new TimerInfo();
173 178
174 ts.localID = localID; 179 ts.localID = localID;
175 ts.itemID = itemID; 180 ts.itemID = itemID;
@@ -183,5 +188,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
183 } 188 }
184 } 189 }
185 } 190 }
191
192 public List<TimerInfo> GetTimersInfo()
193 {
194 List<TimerInfo> retList = new List<TimerInfo>();
195
196 lock (TimerListLock)
197 {
198 foreach (TimerInfo i in Timers.Values)
199 retList.Add(i.Clone());
200 }
201
202 return retList;
203 }
186 } 204 }
187} 205}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index c447d1f..7eb347e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -259,6 +259,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
259 259
260 string osGetScriptEngineName(); 260 string osGetScriptEngineName();
261 string osGetSimulatorVersion(); 261 string osGetSimulatorVersion();
262 string osGetPhysicsEngineType();
262 Object osParseJSONNew(string JSON); 263 Object osParseJSONNew(string JSON);
263 Hashtable osParseJSON(string JSON); 264 Hashtable osParseJSON(string JSON);
264 265
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index afa9ae0..c9902e4 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -420,6 +420,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
420 return m_OSSL_Functions.osGetScriptEngineName(); 420 return m_OSSL_Functions.osGetScriptEngineName();
421 } 421 }
422 422
423 public string osGetPhysicsEngineType()
424 {
425 return m_OSSL_Functions.osGetPhysicsEngineType();
426 }
427
423 public string osGetSimulatorVersion() 428 public string osGetSimulatorVersion()
424 { 429 {
425 return m_OSSL_Functions.osGetSimulatorVersion(); 430 return m_OSSL_Functions.osGetSimulatorVersion();
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/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
index 22804f5..e44a106 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
@@ -82,6 +82,24 @@ namespace OpenSim.Region.ScriptEngine.Shared
82 } 82 }
83 } 83 }
84 84
85 /// <summary>
86 /// Used to signal when the script is stopping in co-operation with the script engine
87 /// (instead of through Thread.Abort()).
88 /// </summary>
89 [Serializable]
90 public class ScriptCoopStopException : Exception
91 {
92 public ScriptCoopStopException()
93 {
94 }
95
96 protected ScriptCoopStopException(
97 SerializationInfo info,
98 StreamingContext context)
99 {
100 }
101 }
102
85 public class DetectParams 103 public class DetectParams
86 { 104 {
87 public const int AGENT = 1; 105 public const int AGENT = 1;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 771db0c..a869a6a 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>();
@@ -156,6 +158,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
156 158
157 public UUID AppDomain { get; set; } 159 public UUID AppDomain { get; set; }
158 160
161 public SceneObjectPart Part { get; private set; }
162
159 public string PrimName { get; private set; } 163 public string PrimName { get; private set; }
160 164
161 public string ScriptName { get; private set; } 165 public string ScriptName { get; private set; }
@@ -174,6 +178,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
174 178
175 public Queue EventQueue { get; private set; } 179 public Queue EventQueue { get; private set; }
176 180
181 public long EventsQueued
182 {
183 get
184 {
185 lock (EventQueue)
186 return EventQueue.Count;
187 }
188 }
189
190 public long EventsProcessed { get; private set; }
191
177 public int StartParam { get; set; } 192 public int StartParam { get; set; }
178 193
179 public TaskInventoryItem ScriptTask { get; private set; } 194 public TaskInventoryItem ScriptTask { get; private set; }
@@ -186,54 +201,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
186 201
187 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; 202 public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute;
188 203
204 private bool m_coopTermination;
205
206 private EventWaitHandle m_coopSleepHandle;
207
189 public void ClearQueue() 208 public void ClearQueue()
190 { 209 {
191 m_TimerQueued = false; 210 m_TimerQueued = false;
192 EventQueue.Clear(); 211 EventQueue.Clear();
193 } 212 }
194 213
195 public ScriptInstance(IScriptEngine engine, SceneObjectPart part, 214 public ScriptInstance(
196 UUID itemID, UUID assetID, string assembly, 215 IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item,
197 AppDomain dom, string primName, string scriptName, 216 int startParam, bool postOnRez,
198 int startParam, bool postOnRez, StateSource stateSource, 217 int maxScriptQueue)
199 int maxScriptQueue)
200 { 218 {
201 State = "default"; 219 State = "default";
202 EventQueue = new Queue(32); 220 EventQueue = new Queue(32);
203 221
204 Engine = engine; 222 Engine = engine;
205 LocalID = part.LocalId; 223 Part = part;
206 ObjectID = part.UUID; 224 ScriptTask = item;
207 RootLocalID = part.ParentGroup.LocalId; 225
208 RootObjectID = part.ParentGroup.UUID; 226 // This is currently only here to allow regression tests to get away without specifying any inventory
209 ItemID = itemID; 227 // item when they are testing script logic that doesn't require an item.
210 AssetID = assetID; 228 if (ScriptTask != null)
211 PrimName = primName; 229 {
212 ScriptName = scriptName; 230 ScriptName = ScriptTask.Name;
213 m_Assembly = assembly; 231 ItemID = ScriptTask.ItemID;
232 AssetID = ScriptTask.AssetID;
233 }
234
235 PrimName = part.ParentGroup.Name;
214 StartParam = startParam; 236 StartParam = startParam;
215 m_MaxScriptQueue = maxScriptQueue; 237 m_MaxScriptQueue = maxScriptQueue;
216 m_stateSource = stateSource;
217 m_postOnRez = postOnRez; 238 m_postOnRez = postOnRez;
218 m_AttachedAvatar = part.ParentGroup.AttachedAvatar; 239 m_AttachedAvatar = part.ParentGroup.AttachedAvatar;
219 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; 240 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID;
220 241
221 if (part != null) 242 if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op")
222 { 243 {
223 part.TaskInventory.LockItemsForRead(true); 244 m_coopTermination = true;
224 if (part.TaskInventory.ContainsKey(ItemID)) 245 m_coopSleepHandle = new AutoResetEvent(false);
225 {
226 ScriptTask = part.TaskInventory[ItemID];
227 }
228 part.TaskInventory.LockItemsForRead(false);
229 } 246 }
247 }
248
249 /// <summary>
250 /// Load the script from an assembly into an AppDomain.
251 /// </summary>
252 /// <param name='dom'></param>
253 /// <param name='assembly'></param>
254 /// <param name='stateSource'></param>
255 public void Load(AppDomain dom, string assembly, StateSource stateSource)
256 {
257 m_Assembly = assembly;
258 m_stateSource = stateSource;
230 259
231 ApiManager am = new ApiManager(); 260 ApiManager am = new ApiManager();
232 261
233 foreach (string api in am.GetApis()) 262 foreach (string api in am.GetApis())
234 { 263 {
235 m_Apis[api] = am.CreateApi(api); 264 m_Apis[api] = am.CreateApi(api);
236 m_Apis[api].Initialize(engine, part, ScriptTask); 265 m_Apis[api].Initialize(Engine, Part, ScriptTask, m_coopSleepHandle);
237 } 266 }
238 267
239 try 268 try
@@ -267,7 +296,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
267 296
268// // m_log.Debug("[Script] Script instance created"); 297// // m_log.Debug("[Script] Script instance created");
269 298
270 part.SetScriptEvents(ItemID, 299 Part.SetScriptEvents(ItemID,
271 (int)m_Script.GetStateEventFlags(State)); 300 (int)m_Script.GetStateEventFlags(State));
272 } 301 }
273 catch (Exception e) 302 catch (Exception e)
@@ -309,7 +338,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
309 338
310// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); 339// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName);
311 340
312 part.SetScriptEvents(ItemID, 341 Part.SetScriptEvents(ItemID,
313 (int)m_Script.GetStateEventFlags(State)); 342 (int)m_Script.GetStateEventFlags(State));
314 343
315 if (!Running) 344 if (!Running)
@@ -521,9 +550,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
521 } 550 }
522 551
523 // Wait for the current event to complete. 552 // Wait for the current event to complete.
524 if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) 553 if (!m_InSelfDelete)
525 { 554 {
526 return true; 555 if (!m_coopTermination)
556 {
557 // If we're not co-operative terminating then try and wait for the event to complete before stopping
558 if (workItem.Wait(new TimeSpan((long)timeout * 100000)))
559 return true;
560 }
561 else
562 {
563 m_log.DebugFormat(
564 "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}",
565 ScriptName, ItemID, PrimName, ObjectID);
566
567 // This will terminate the event on next handle check by the script.
568 m_coopSleepHandle.Set();
569
570 // For now, we will wait forever since the event should always cleanly terminate once LSL loop
571 // checking is implemented. May want to allow a shorter timeout option later.
572 if (workItem.Wait(TimeSpan.MaxValue))
573 {
574 m_log.DebugFormat(
575 "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}",
576 ScriptName, ItemID, PrimName, ObjectID);
577
578 return true;
579 }
580 }
527 } 581 }
528 582
529 lock (EventQueue) 583 lock (EventQueue)
@@ -536,11 +590,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
536 590
537 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then 591 // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then
538 // forcibly abort the work item (this aborts the underlying thread). 592 // forcibly abort the work item (this aborts the underlying thread).
593 // Co-operative termination should never reach this point.
539 if (!m_InSelfDelete) 594 if (!m_InSelfDelete)
540 { 595 {
541// m_log.ErrorFormat( 596 m_log.DebugFormat(
542// "[SCRIPT INSTANCE]: Aborting script {0} {1} in prim {2} {3} {4} {5}", 597 "[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); 598 ScriptName, ItemID, PrimName, LocalID, timeout);
544 599
545 workItem.Abort(); 600 workItem.Abort();
546 } 601 }
@@ -696,19 +751,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
696 { 751 {
697 752
698// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); 753// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
754 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
755
756 if (DebugLevel >= 2)
757 m_log.DebugFormat(
758 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
759 data.EventName,
760 ScriptName,
761 part.Name,
762 part.LocalId,
763 part.ParentGroup.Name,
764 part.ParentGroup.UUID,
765 part.AbsolutePosition,
766 part.ParentGroup.Scene.Name);
699 767
700 m_DetectParams = data.DetectParams; 768 m_DetectParams = data.DetectParams;
701 769
702 if (data.EventName == "state") // Hardcoded state change 770 if (data.EventName == "state") // Hardcoded state change
703 { 771 {
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(); 772 State = data.Params[0].ToString();
773
774 if (DebugLevel >= 1)
775 m_log.DebugFormat(
776 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
777 State,
778 ScriptName,
779 part.Name,
780 part.LocalId,
781 part.ParentGroup.Name,
782 part.ParentGroup.UUID,
783 part.AbsolutePosition,
784 part.ParentGroup.Scene.Name);
785
707 AsyncCommandManager.RemoveScript(Engine, 786 AsyncCommandManager.RemoveScript(Engine,
708 LocalID, ItemID); 787 LocalID, ItemID);
709 788
710 SceneObjectPart part = Engine.World.GetSceneObjectPart(
711 LocalID);
712 if (part != null) 789 if (part != null)
713 { 790 {
714 part.SetScriptEvents(ItemID, 791 part.SetScriptEvents(ItemID,
@@ -720,8 +797,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
720 if (Engine.World.PipeEventsForScript(LocalID) || 797 if (Engine.World.PipeEventsForScript(LocalID) ||
721 data.EventName == "control") // Don't freeze avies! 798 data.EventName == "control") // Don't freeze avies!
722 { 799 {
723 SceneObjectPart part = Engine.World.GetSceneObjectPart(
724 LocalID);
725 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", 800 // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
726 // PrimName, ScriptName, data.EventName, State); 801 // PrimName, ScriptName, data.EventName, State);
727 802
@@ -763,7 +838,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
763 m_InEvent = false; 838 m_InEvent = false;
764 m_CurrentEvent = String.Empty; 839 m_CurrentEvent = String.Empty;
765 840
766 if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) 841 if ((!(e is TargetInvocationException)
842 || (!(e.InnerException is SelfDeleteException)
843 && !(e.InnerException is ScriptDeleteException)
844 && !(e.InnerException is ScriptCoopStopException)))
845 && !(e is ThreadAbortException))
767 { 846 {
768 try 847 try
769 { 848 {
@@ -776,6 +855,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
776 ChatTypeEnum.DebugChannel, 2147483647, 855 ChatTypeEnum.DebugChannel, 2147483647,
777 part.AbsolutePosition, 856 part.AbsolutePosition,
778 part.Name, part.UUID, false); 857 part.Name, part.UUID, false);
858
859
860 m_log.DebugFormat(
861 "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
862 ScriptName,
863 PrimName,
864 part.UUID,
865 part.AbsolutePosition,
866 part.ParentGroup.Scene.Name,
867 text.Replace("\n", "\\n"),
868 e.InnerException);
779 } 869 }
780 catch (Exception) 870 catch (Exception)
781 { 871 {
@@ -802,6 +892,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
802 if (part != null) 892 if (part != null)
803 part.Inventory.RemoveInventoryItem(ItemID); 893 part.Inventory.RemoveInventoryItem(ItemID);
804 } 894 }
895 else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException))
896 {
897 m_log.DebugFormat(
898 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
899 PrimName, ScriptName, data.EventName, State);
900 }
805 } 901 }
806 } 902 }
807 } 903 }
@@ -810,6 +906,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
810 // script engine to run the next event. 906 // script engine to run the next event.
811 lock (EventQueue) 907 lock (EventQueue)
812 { 908 {
909 EventsProcessed++;
910
813 if (EventQueue.Count > 0 && Running && !ShuttingDown) 911 if (EventQueue.Count > 0 && Running && !ShuttingDown)
814 { 912 {
815 m_CurrentWorkItem = Engine.QueueEventHandler(this); 913 m_CurrentWorkItem = Engine.QueueEventHandler(this);
@@ -834,7 +932,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
834 return (DateTime.Now - m_EventStart).Seconds; 932 return (DateTime.Now - m_EventStart).Seconds;
835 } 933 }
836 934
837 public void ResetScript() 935 public void ResetScript(int timeout)
838 { 936 {
839 if (m_Script == null) 937 if (m_Script == null)
840 return; 938 return;
@@ -844,7 +942,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
844 RemoveState(); 942 RemoveState();
845 ReleaseControls(); 943 ReleaseControls();
846 944
847 Stop(0); 945 Stop(timeout);
848 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); 946 SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID);
849 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; 947 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
850 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; 948 part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero;
@@ -1015,7 +1113,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1015 "({0}): {1}", scriptLine - 1, 1113 "({0}): {1}", scriptLine - 1,
1016 e.InnerException.Message); 1114 e.InnerException.Message);
1017 1115
1018 System.Console.WriteLine(e.ToString()+"\n");
1019 return message; 1116 return message;
1020 } 1117 }
1021 } 1118 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index c9c4753..2e61fb8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -633,19 +633,44 @@ namespace OpenSim.Region.ScriptEngine.Shared
633 633
634 public LSL_Types.Vector3 GetVector3Item(int itemIndex) 634 public LSL_Types.Vector3 GetVector3Item(int itemIndex)
635 { 635 {
636 if(m_data[itemIndex] is LSL_Types.Vector3) 636 if (m_data[itemIndex] is LSL_Types.Vector3)
637 {
637 return (LSL_Types.Vector3)m_data[itemIndex]; 638 return (LSL_Types.Vector3)m_data[itemIndex];
639 }
640 else if(m_data[itemIndex] is OpenMetaverse.Vector3)
641 {
642 return new LSL_Types.Vector3(
643 (OpenMetaverse.Vector3)m_data[itemIndex]);
644 }
638 else 645 else
646 {
639 throw new InvalidCastException(string.Format( 647 throw new InvalidCastException(string.Format(
640 "{0} expected but {1} given", 648 "{0} expected but {1} given",
641 typeof(LSL_Types.Vector3).Name, 649 typeof(LSL_Types.Vector3).Name,
642 m_data[itemIndex] != null ? 650 m_data[itemIndex] != null ?
643 m_data[itemIndex].GetType().Name : "null")); 651 m_data[itemIndex].GetType().Name : "null"));
652 }
644 } 653 }
645 654
646 public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) 655 public LSL_Types.Quaternion GetQuaternionItem(int itemIndex)
647 { 656 {
648 return (LSL_Types.Quaternion)m_data[itemIndex]; 657 if (m_data[itemIndex] is LSL_Types.Quaternion)
658 {
659 return (LSL_Types.Quaternion)m_data[itemIndex];
660 }
661 else if(m_data[itemIndex] is OpenMetaverse.Quaternion)
662 {
663 return new LSL_Types.Quaternion(
664 (OpenMetaverse.Quaternion)m_data[itemIndex]);
665 }
666 else
667 {
668 throw new InvalidCastException(string.Format(
669 "{0} expected but {1} given",
670 typeof(LSL_Types.Quaternion).Name,
671 m_data[itemIndex] != null ?
672 m_data[itemIndex].GetType().Name : "null"));
673 }
649 } 674 }
650 675
651 public LSL_Types.key GetKeyItem(int itemIndex) 676 public LSL_Types.key GetKeyItem(int itemIndex)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
index c73e22f..6dd6c17 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.ScriptEngine.Shared; 42using OpenSim.Region.ScriptEngine.Shared;
43using OpenSim.Region.ScriptEngine.Shared.Api; 43using OpenSim.Region.ScriptEngine.Shared.Api;
44using OpenSim.Region.ScriptEngine.Shared.Instance;
44using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 46using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock; 47using OpenSim.Tests.Common.Mock;
@@ -51,14 +52,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
51 /// Tests for inventory functions in LSL 52 /// Tests for inventory functions in LSL
52 /// </summary> 53 /// </summary>
53 [TestFixture] 54 [TestFixture]
54 public class LSL_ApiInventoryTests 55 public class LSL_ApiInventoryTests : OpenSimTestCase
55 { 56 {
56 protected Scene m_scene; 57 protected Scene m_scene;
57 protected XEngine.XEngine m_engine; 58 protected XEngine.XEngine m_engine;
58 59
59 [SetUp] 60 [SetUp]
60 public void SetUp() 61 public override void SetUp()
61 { 62 {
63 base.SetUp();
64
62 IConfigSource initConfigSource = new IniConfigSource(); 65 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 66 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 67 config.Set("Enabled", "true");
@@ -91,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
91 TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); 94 TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId);
92 95
93 LSL_Api api = new LSL_Api(); 96 LSL_Api api = new LSL_Api();
94 api.Initialize(m_engine, so1.RootPart, null); 97 api.Initialize(m_engine, so1.RootPart, null, null);
95 98
96 // Create a second object 99 // Create a second object
97 SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); 100 SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100);
@@ -124,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
124 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); 127 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10);
125 m_scene.AddSceneObject(so1); 128 m_scene.AddSceneObject(so1);
126 LSL_Api api = new LSL_Api(); 129 LSL_Api api = new LSL_Api();
127 api.Initialize(m_engine, so1.RootPart, null); 130 api.Initialize(m_engine, so1.RootPart, null, null);
128 131
129 // Create an object embedded inside the first 132 // Create an object embedded inside the first
130 UUID itemId = TestHelpers.ParseTail(0x20); 133 UUID itemId = TestHelpers.ParseTail(0x20);
@@ -134,7 +137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
134 SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); 137 SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100);
135 m_scene.AddSceneObject(so2); 138 m_scene.AddSceneObject(so2);
136 LSL_Api api2 = new LSL_Api(); 139 LSL_Api api2 = new LSL_Api();
137 api2.Initialize(m_engine, so2.RootPart, null); 140 api2.Initialize(m_engine, so2.RootPart, null, null);
138 141
139 // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** 142 // *** Firstly, we test where llAllowInventoryDrop() has not been called. ***
140 api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); 143 api.llGiveInventory(so2.UUID.ToString(), inventoryItemName);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
index 2565ae7..5b57bbe 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.ScriptEngine.Shared; 42using OpenSim.Region.ScriptEngine.Shared;
43using OpenSim.Region.ScriptEngine.Shared.Api; 43using OpenSim.Region.ScriptEngine.Shared.Api;
44using OpenSim.Region.ScriptEngine.Shared.Instance;
44using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 45using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
45using OpenSim.Services.Interfaces; 46using OpenSim.Services.Interfaces;
46using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
@@ -56,14 +57,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
56 /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. 57 /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests.
57 /// </remarks> 58 /// </remarks>
58 [TestFixture] 59 [TestFixture]
59 public class LSL_ApiLinkingTests 60 public class LSL_ApiLinkingTests : OpenSimTestCase
60 { 61 {
61 protected Scene m_scene; 62 protected Scene m_scene;
62 protected XEngine.XEngine m_engine; 63 protected XEngine.XEngine m_engine;
63 64
64 [SetUp] 65 [SetUp]
65 public void SetUp() 66 public override void SetUp()
66 { 67 {
68 base.SetUp();
69
67 IConfigSource initConfigSource = new IniConfigSource(); 70 IConfigSource initConfigSource = new IniConfigSource();
68 IConfig config = initConfigSource.AddConfig("XEngine"); 71 IConfig config = initConfigSource.AddConfig("XEngine");
69 config.Set("Enabled", "true"); 72 config.Set("Enabled", "true");
@@ -102,7 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
102 m_scene.AddSceneObject(grp2); 105 m_scene.AddSceneObject(grp2);
103 106
104 LSL_Api apiGrp1 = new LSL_Api(); 107 LSL_Api apiGrp1 = new LSL_Api();
105 apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); 108 apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null);
106 109
107 apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); 110 apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE);
108 111
@@ -129,7 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
129 grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 132 grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
130 133
131 LSL_Api apiGrp1 = new LSL_Api(); 134 LSL_Api apiGrp1 = new LSL_Api();
132 apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); 135 apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item, null);
133 136
134 apiGrp1.llBreakLink(2); 137 apiGrp1.llBreakLink(2);
135 138
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
index dd23be8..60de5cb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
@@ -34,6 +34,7 @@ using OpenSim.Region.ScriptEngine.Shared;
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35using Nini.Config; 35using Nini.Config;
36using OpenSim.Region.ScriptEngine.Shared.Api; 36using OpenSim.Region.ScriptEngine.Shared.Api;
37using OpenSim.Region.ScriptEngine.Shared.Instance;
37using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 38using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
38using OpenMetaverse; 39using OpenMetaverse;
39using OpenSim.Tests.Common.Mock; 40using OpenSim.Tests.Common.Mock;
@@ -46,13 +47,15 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
46namespace OpenSim.Region.ScriptEngine.Shared.Tests 47namespace OpenSim.Region.ScriptEngine.Shared.Tests
47{ 48{
48 [TestFixture] 49 [TestFixture]
49 public class LSL_ApiListTests 50 public class LSL_ApiListTests : OpenSimTestCase
50 { 51 {
51 private LSL_Api m_lslApi; 52 private LSL_Api m_lslApi;
52 53
53 [SetUp] 54 [SetUp]
54 public void SetUp() 55 public override void SetUp()
55 { 56 {
57 base.SetUp();
58
56 IConfigSource initConfigSource = new IniConfigSource(); 59 IConfigSource initConfigSource = new IniConfigSource();
57 IConfig config = initConfigSource.AddConfig("XEngine"); 60 IConfig config = initConfigSource.AddConfig("XEngine");
58 config.Set("Enabled", "true"); 61 config.Set("Enabled", "true");
@@ -65,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
65 engine.AddRegion(scene); 68 engine.AddRegion(scene);
66 69
67 m_lslApi = new LSL_Api(); 70 m_lslApi = new LSL_Api();
68 m_lslApi.Initialize(engine, part, null); 71 m_lslApi.Initialize(engine, part, null, null);
69 } 72 }
70 73
71 [Test] 74 [Test]
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs
index c41d1e7..e97ae06 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs
@@ -33,6 +33,7 @@ using OpenSim.Region.ScriptEngine.Shared;
33using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
34using Nini.Config; 34using Nini.Config;
35using OpenSim.Region.ScriptEngine.Shared.Api; 35using OpenSim.Region.ScriptEngine.Shared.Api;
36using OpenSim.Region.ScriptEngine.Shared.Instance;
36using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 37using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
37using OpenMetaverse; 38using OpenMetaverse;
38using System; 39using System;
@@ -66,7 +67,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
66 engine.AddRegion(scene); 67 engine.AddRegion(scene);
67 68
68 m_lslApi = new LSL_Api(); 69 m_lslApi = new LSL_Api();
69 m_lslApi.Initialize(engine, part, null); 70 m_lslApi.Initialize(engine, part, null, null);
70 } 71 }
71 72
72 [Test] 73 [Test]
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..c88bad5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
@@ -41,6 +41,7 @@ using OpenSim.Region.OptionalModules.World.NPC;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.ScriptEngine.Shared; 42using OpenSim.Region.ScriptEngine.Shared;
43using OpenSim.Region.ScriptEngine.Shared.Api; 43using OpenSim.Region.ScriptEngine.Shared.Api;
44using OpenSim.Region.ScriptEngine.Shared.Instance;
44using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 46using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock; 47using OpenSim.Tests.Common.Mock;
@@ -51,14 +52,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
51 /// Tests for OSSL_Api 52 /// Tests for OSSL_Api
52 /// </summary> 53 /// </summary>
53 [TestFixture] 54 [TestFixture]
54 public class OSSL_ApiAppearanceTest 55 public class OSSL_ApiAppearanceTest : OpenSimTestCase
55 { 56 {
56 protected Scene m_scene; 57 protected Scene m_scene;
57 protected XEngine.XEngine m_engine; 58 protected XEngine.XEngine m_engine;
58 59
59 [SetUp] 60 [SetUp]
60 public void SetUp() 61 public override void SetUp()
61 { 62 {
63 base.SetUp();
64
62 IConfigSource initConfigSource = new IniConfigSource(); 65 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 66 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 67 config.Set("Enabled", "true");
@@ -91,7 +94,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
91 m_scene.AddSceneObject(so); 94 m_scene.AddSceneObject(so);
92 95
93 OSSL_Api osslApi = new OSSL_Api(); 96 OSSL_Api osslApi = new OSSL_Api();
94 osslApi.Initialize(m_engine, part, null); 97 osslApi.Initialize(m_engine, part, null, null);
95 98
96 string notecardName = "appearanceNc"; 99 string notecardName = "appearanceNc";
97 100
@@ -132,7 +135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
132 m_scene.AddSceneObject(so); 135 m_scene.AddSceneObject(so);
133 136
134 OSSL_Api osslApi = new OSSL_Api(); 137 OSSL_Api osslApi = new OSSL_Api();
135 osslApi.Initialize(m_engine, part, null); 138 osslApi.Initialize(m_engine, part, null, null);
136 139
137 string notecardName = "appearanceNc"; 140 string notecardName = "appearanceNc";
138 141
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
index 5ed1f3d..b2803a1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
@@ -41,6 +41,7 @@ using OpenSim.Region.CoreModules.Framework.InventoryAccess;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.ScriptEngine.Shared; 42using OpenSim.Region.ScriptEngine.Shared;
43using OpenSim.Region.ScriptEngine.Shared.Api; 43using OpenSim.Region.ScriptEngine.Shared.Api;
44using OpenSim.Region.ScriptEngine.Shared.Instance;
44using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 46using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock; 47using OpenSim.Tests.Common.Mock;
@@ -98,9 +99,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
98 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); 99 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID);
99 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); 100 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart);
100 101
101 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); 102 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
102 OSSL_Api osslApi = new OSSL_Api(); 103 OSSL_Api osslApi = new OSSL_Api();
103 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); 104 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
104 105
105// SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); 106// SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID);
106 107
@@ -144,9 +145,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
144 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); 145 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID);
145 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); 146 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart);
146 147
147 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); 148 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
148 OSSL_Api osslApi = new OSSL_Api(); 149 OSSL_Api osslApi = new OSSL_Api();
149 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); 150 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
150 151
151 // Create an object embedded inside the first 152 // Create an object embedded inside the first
152 TaskInventoryHelpers.AddNotecard( 153 TaskInventoryHelpers.AddNotecard(
@@ -192,12 +193,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
192 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); 193 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID);
193 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); 194 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart);
194 195
195 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); 196 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
196 OSSL_Api osslApi = new OSSL_Api(); 197 OSSL_Api osslApi = new OSSL_Api();
197 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); 198 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem, null);
198 199
199 // Create an object embedded inside the first 200 // Create an object embedded inside the first
200 TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); 201 TaskInventoryHelpers.AddSceneObject(
202 m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID);
201 203
202 ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); 204 ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2);
203 205
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
index b49bcc2..1f8a6e5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
@@ -42,6 +42,7 @@ using OpenSim.Region.OptionalModules.World.NPC;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.ScriptEngine.Shared; 43using OpenSim.Region.ScriptEngine.Shared;
44using OpenSim.Region.ScriptEngine.Shared.Api; 44using OpenSim.Region.ScriptEngine.Shared.Api;
45using OpenSim.Region.ScriptEngine.Shared.Instance;
45using OpenSim.Region.ScriptEngine.Shared.ScriptBase; 46using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
46using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
47using OpenSim.Tests.Common; 48using OpenSim.Tests.Common;
@@ -99,7 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
99 m_scene.AddSceneObject(so); 100 m_scene.AddSceneObject(so);
100 101
101 OSSL_Api osslApi = new OSSL_Api(); 102 OSSL_Api osslApi = new OSSL_Api();
102 osslApi.Initialize(m_engine, part, null); 103 osslApi.Initialize(m_engine, part, null, null);
103 104
104 string notecardName = "appearanceNc"; 105 string notecardName = "appearanceNc";
105 osslApi.osOwnerSaveAppearance(notecardName); 106 osslApi.osOwnerSaveAppearance(notecardName);
@@ -125,14 +126,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
125 m_scene.AddSceneObject(so); 126 m_scene.AddSceneObject(so);
126 127
127 OSSL_Api osslApi = new OSSL_Api(); 128 OSSL_Api osslApi = new OSSL_Api();
128 osslApi.Initialize(m_engine, so.RootPart, null); 129 osslApi.Initialize(m_engine, so.RootPart, null, null);
129 130
130 string npcRaw;
131 bool gotExpectedException = false; 131 bool gotExpectedException = false;
132 try 132 try
133 { 133 {
134 npcRaw 134 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 } 135 }
137 catch (ScriptException) 136 catch (ScriptException)
138 { 137 {
@@ -162,7 +161,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
162 m_scene.AddSceneObject(so); 161 m_scene.AddSceneObject(so);
163 162
164 OSSL_Api osslApi = new OSSL_Api(); 163 OSSL_Api osslApi = new OSSL_Api();
165 osslApi.Initialize(m_engine, part, null); 164 osslApi.Initialize(m_engine, part, null, null);
166 165
167 string notecardName = "appearanceNc"; 166 string notecardName = "appearanceNc";
168 osslApi.osOwnerSaveAppearance(notecardName); 167 osslApi.osOwnerSaveAppearance(notecardName);
@@ -196,7 +195,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
196 m_scene.AddSceneObject(so); 195 m_scene.AddSceneObject(so);
197 196
198 OSSL_Api osslApi = new OSSL_Api(); 197 OSSL_Api osslApi = new OSSL_Api();
199 osslApi.Initialize(m_engine, part, null); 198 osslApi.Initialize(m_engine, part, null, null);
200 199
201 osslApi.osOwnerSaveAppearance(firstAppearanceNcName); 200 osslApi.osOwnerSaveAppearance(firstAppearanceNcName);
202 201
@@ -234,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
234 m_scene.AddSceneObject(so); 233 m_scene.AddSceneObject(so);
235 234
236 OSSL_Api osslApi = new OSSL_Api(); 235 OSSL_Api osslApi = new OSSL_Api();
237 osslApi.Initialize(m_engine, part, null); 236 osslApi.Initialize(m_engine, part, null, null);
238 237
239 osslApi.osOwnerSaveAppearance(firstAppearanceNcName); 238 osslApi.osOwnerSaveAppearance(firstAppearanceNcName);
240 239
@@ -286,10 +285,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
286 m_scene.AddSceneObject(otherSo); 285 m_scene.AddSceneObject(otherSo);
287 286
288 OSSL_Api osslApi = new OSSL_Api(); 287 OSSL_Api osslApi = new OSSL_Api();
289 osslApi.Initialize(m_engine, part, null); 288 osslApi.Initialize(m_engine, part, null, null);
290 289
291 OSSL_Api otherOsslApi = new OSSL_Api(); 290 OSSL_Api otherOsslApi = new OSSL_Api();
292 otherOsslApi.Initialize(m_engine, otherPart, null); 291 otherOsslApi.Initialize(m_engine, otherPart, null, null);
293 292
294 string notecardName = "appearanceNc"; 293 string notecardName = "appearanceNc";
295 osslApi.osOwnerSaveAppearance(notecardName); 294 osslApi.osOwnerSaveAppearance(notecardName);
@@ -333,7 +332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
333 m_scene.AddSceneObject(so); 332 m_scene.AddSceneObject(so);
334 333
335 OSSL_Api osslApi = new OSSL_Api(); 334 OSSL_Api osslApi = new OSSL_Api();
336 osslApi.Initialize(m_engine, part, null); 335 osslApi.Initialize(m_engine, part, null, null);
337 336
338 string notecardName = "appearanceNc"; 337 string notecardName = "appearanceNc";
339 osslApi.osOwnerSaveAppearance(notecardName); 338 osslApi.osOwnerSaveAppearance(notecardName);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs
new file mode 100644
index 0000000..efb854d
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs
@@ -0,0 +1,126 @@
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 OpenSim.Framework;
31using OpenSim.Framework.Console;
32using OpenSim.Region.ScriptEngine.Interfaces;
33using OpenSim.Region.ScriptEngine.Shared.Api;
34using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
35
36namespace OpenSim.Region.ScriptEngine.XEngine
37{
38 public class ScriptEngineConsoleCommands
39 {
40 IScriptEngine m_engine;
41
42 public ScriptEngineConsoleCommands(IScriptEngine engine)
43 {
44 m_engine = engine;
45 }
46
47 public void RegisterCommands()
48 {
49 MainConsole.Instance.Commands.AddCommand(
50 "Scripts", false, "show script sensors", "show script sensors", "Show script sensors information",
51 HandleShowSensors);
52
53 MainConsole.Instance.Commands.AddCommand(
54 "Scripts", false, "show script timers", "show script timers", "Show script sensors information",
55 HandleShowTimers);
56 }
57
58 private bool IsSceneSelected()
59 {
60 return MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_engine.World;
61 }
62
63 private void HandleShowSensors(string module, string[] cmdparams)
64 {
65 if (!IsSceneSelected())
66 return;
67
68 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(m_engine);
69
70 if (sr == null)
71 {
72 MainConsole.Instance.Output("Plugin not yet initialized");
73 return;
74 }
75
76 List<SensorRepeat.SensorInfo> sensorInfo = sr.GetSensorInfo();
77
78 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
79 cdt.AddColumn("Part name", 40);
80 cdt.AddColumn("Script item ID", 36);
81 cdt.AddColumn("Type", 4);
82 cdt.AddColumn("Interval", 8);
83 cdt.AddColumn("Range", 8);
84 cdt.AddColumn("Arc", 8);
85
86 foreach (SensorRepeat.SensorInfo s in sensorInfo)
87 {
88 cdt.AddRow(s.host.Name, s.itemID, s.type, s.interval, s.range, s.arc);
89 }
90
91 MainConsole.Instance.Output(cdt.ToString());
92 MainConsole.Instance.OutputFormat("Total: {0}", sensorInfo.Count);
93 }
94
95 private void HandleShowTimers(string module, string[] cmdparams)
96 {
97 if (!IsSceneSelected())
98 return;
99
100 Timer timerPlugin = AsyncCommandManager.GetTimerPlugin(m_engine);
101
102 if (timerPlugin == null)
103 {
104 MainConsole.Instance.Output("Plugin not yet initialized");
105 return;
106 }
107
108 List<Timer.TimerInfo> timersInfo = timerPlugin.GetTimersInfo();
109
110 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
111 cdt.AddColumn("Part local ID", 13);
112 cdt.AddColumn("Script item ID", 36);
113 cdt.AddColumn("Interval", 10);
114 cdt.AddColumn("Next", 8);
115
116 foreach (Timer.TimerInfo t in timersInfo)
117 {
118 // Convert from 100 ns ticks back to seconds
119 cdt.AddRow(t.localID, t.itemID, (double)t.interval / 10000000, t.next);
120 }
121
122 MainConsole.Instance.Output(cdt.ToString());
123 MainConsole.Instance.OutputFormat("Total: {0}", timersInfo.Count);
124 }
125 }
126} \ No newline at end of file
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..2065a46 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>();
@@ -218,6 +237,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
218 } 237 }
219 } 238 }
220 239
240 private ScriptEngineConsoleCommands m_consoleCommands;
241
221 public string ScriptEngineName 242 public string ScriptEngineName
222 { 243 {
223 get { return "XEngine"; } 244 get { return "XEngine"; }
@@ -316,6 +337,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
316 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); 337 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
317 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false); 338 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
318 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000; 339 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
340 m_WaitForEventCompletionOnScriptStop
341 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
342
319 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines"); 343 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
320 344
321 m_Prio = ThreadPriority.BelowNormal; 345 m_Prio = ThreadPriority.BelowNormal;
@@ -364,48 +388,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine
364 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved; 388 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
365 } 389 }
366 390
391 m_consoleCommands = new ScriptEngineConsoleCommands(this);
392 m_consoleCommands.RegisterCommands();
393
367 MainConsole.Instance.Commands.AddCommand( 394 MainConsole.Instance.Commands.AddCommand(
368 "Scripts", false, "xengine status", "xengine status", "Show status information", 395 "Scripts", false, "xengine status", "xengine status", "Show status information",
369 "Show status information on the script engine.", 396 "Show status information on the script engine.",
370 HandleShowStatus); 397 HandleShowStatus);
371 398
372 MainConsole.Instance.Commands.AddCommand( 399 MainConsole.Instance.Commands.AddCommand(
373 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>]", "Show script information", 400 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
374 "Show information on all scripts known to the script engine." 401 "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.", 402 + "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
376 HandleShowScripts); 403 HandleShowScripts);
377 404
378 MainConsole.Instance.Commands.AddCommand( 405 MainConsole.Instance.Commands.AddCommand(
379 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>]", "Show script information", 406 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
380 "Synonym for scripts show command", HandleShowScripts); 407 "Synonym for scripts show command", HandleShowScripts);
381 408
382 MainConsole.Instance.Commands.AddCommand( 409 MainConsole.Instance.Commands.AddCommand(
383 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>]", "Suspends all running scripts", 410 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts",
384 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a" 411 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
385 + " script that is currently processing an event.\n" 412 + " script that is currently processing an event.\n"
386 + "Suspended scripts will continue to accumulate events but won't process them.\n" 413 + "Suspended scripts will continue to accumulate events but won't process them.\n"
387 + "If a <script-item-uuid> is given then only that script will be suspended. Otherwise, all suitable scripts are suspended.", 414 + "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
388 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript)); 415 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
389 416
390 MainConsole.Instance.Commands.AddCommand( 417 MainConsole.Instance.Commands.AddCommand(
391 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>]", "Resumes all suspended scripts", 418 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
392 "Resumes all currently suspended scripts.\n" 419 "Resumes all currently suspended scripts.\n"
393 + "Resumed scripts will process all events accumulated whilst suspended." 420 + "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.", 421 + "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
395 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript)); 422 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
396 423
397 MainConsole.Instance.Commands.AddCommand( 424 MainConsole.Instance.Commands.AddCommand(
398 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>]", "Stops all running scripts", 425 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
399 "Stops all running scripts." 426 "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.", 427 + "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
401 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript)); 428 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
402 429
403 MainConsole.Instance.Commands.AddCommand( 430 MainConsole.Instance.Commands.AddCommand(
404 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>]", "Starts all stopped scripts", 431 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
405 "Starts all stopped scripts." 432 "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.", 433 + "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.",
407 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); 434 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
408 435
436 MainConsole.Instance.Commands.AddCommand(
437 "Scripts", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a script",
438 "Activates or deactivates extra debug logging for the given script.\n"
439 + "Level == 0, deactivate extra debug logging.\n"
440 + "Level >= 1, log state changes.\n"
441 + "Level >= 2, log event invocations.\n",
442 HandleDebugScriptLogCommand);
443
409// MainConsole.Instance.Commands.AddCommand( 444// MainConsole.Instance.Commands.AddCommand(
410// "Debug", false, "debug xengine", "debug xengine [<level>]", 445// "Debug", false, "debug xengine", "debug xengine [<level>]",
411// "Turn on detailed xengine debugging.", 446// "Turn on detailed xengine debugging.",
@@ -414,6 +449,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine
414// HandleDebugLevelCommand); 449// HandleDebugLevelCommand);
415 } 450 }
416 451
452 private void HandleDebugScriptLogCommand(string module, string[] args)
453 {
454 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
455 return;
456
457 if (args.Length != 5)
458 {
459 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
460 return;
461 }
462
463 UUID itemId;
464
465 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
466 return;
467
468 int newLevel;
469
470 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
471 return;
472
473 IScriptInstance si;
474
475 lock (m_Scripts)
476 {
477 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
478 // engine
479 if (!m_Scripts.TryGetValue(itemId, out si))
480 return;
481 }
482
483 si.DebugLevel = newLevel;
484 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
485 }
486
417 /// <summary> 487 /// <summary>
418 /// Change debug level 488 /// Change debug level
419 /// </summary> 489 /// </summary>
@@ -445,9 +515,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
445 /// </summary> 515 /// </summary>
446 /// <param name="cmdparams"></param> 516 /// <param name="cmdparams"></param>
447 /// <param name="instance"></param> 517 /// <param name="instance"></param>
448 /// <returns>true if we're okay to proceed, false if not.</returns> 518 /// <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) 519 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
450 { 520 {
521 HandleScriptsAction<object>(cmdparams, action, null);
522 }
523
524 /// <summary>
525 /// Parse the raw item id into a script instance from the command params if it's present.
526 /// </summary>
527 /// <param name="cmdparams"></param>
528 /// <param name="instance"></param>
529 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
530 private void HandleScriptsAction<TKey>(
531 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
532 {
451 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 533 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
452 return; 534 return;
453 535
@@ -458,35 +540,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine
458 540
459 if (cmdparams.Length == 2) 541 if (cmdparams.Length == 2)
460 { 542 {
461 foreach (IScriptInstance instance in m_Scripts.Values) 543 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
544
545 if (keySelector != null)
546 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
547
548 foreach (IScriptInstance instance in scripts)
462 action(instance); 549 action(instance);
463 550
464 return; 551 return;
465 } 552 }
466 553
467 rawItemId = cmdparams[2]; 554 for (int i = 2; i < cmdparams.Length; i++)
468
469 if (!UUID.TryParse(rawItemId, out itemId))
470 {
471 MainConsole.Instance.OutputFormat("Error - {0} is not a valid UUID", rawItemId);
472 return;
473 }
474
475 if (itemId != UUID.Zero)
476 { 555 {
477 IScriptInstance instance = GetInstance(itemId); 556 rawItemId = cmdparams[i];
478 if (instance == null) 557
558 if (!UUID.TryParse(rawItemId, out itemId))
479 { 559 {
480 // Commented out for now since this will cause false reports on simulators with more than 560 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
481 // one scene where the current command line set region is 'root' (which causes commands to 561 continue;
482 // go to both regions... (sigh)
483// MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
484 return;
485 } 562 }
486 else 563
564 if (itemId != UUID.Zero)
487 { 565 {
488 action(instance); 566 IScriptInstance instance = GetInstance(itemId);
489 return; 567 if (instance == null)
568 {
569 // Commented out for now since this will cause false reports on simulators with more than
570 // one scene where the current command line set region is 'root' (which causes commands to
571 // go to both regions... (sigh)
572 // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
573 continue;
574 }
575 else
576 {
577 action(instance);
578 }
490 } 579 }
491 } 580 }
492 } 581 }
@@ -505,9 +594,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
505 StringBuilder sb = new StringBuilder(); 594 StringBuilder sb = new StringBuilder();
506 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); 595 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
507 596
597 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
598
508 lock (m_Scripts) 599 lock (m_Scripts)
509 sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); 600 {
601 scriptsLoaded = m_Scripts.Count;
510 602
603 foreach (IScriptInstance si in m_Scripts.Values)
604 {
605 eventsQueued += si.EventsQueued;
606 eventsProcessed += si.EventsProcessed;
607 }
608 }
609
610 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
511 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); 611 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
512 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); 612 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
513 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); 613 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@@ -516,6 +616,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
516 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); 616 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
517 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); 617 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
518// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); 618// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
619 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
620 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
519 621
520 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); 622 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
521 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); 623 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@@ -546,7 +648,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
546 } 648 }
547 } 649 }
548 650
549 HandleScriptsAction(cmdparams, HandleShowScript); 651 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
550 } 652 }
551 653
552 private void HandleShowScript(IScriptInstance instance) 654 private void HandleShowScript(IScriptInstance instance)
@@ -576,11 +678,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
576 678
577 sb.AppendFormat("Script name : {0}\n", instance.ScriptName); 679 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
578 sb.AppendFormat("Status : {0}\n", status); 680 sb.AppendFormat("Status : {0}\n", status);
579 681 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
580 lock (eq) 682 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); 683 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
684 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
584 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 685 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
585 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 686 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
586 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); 687 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
@@ -1089,8 +1190,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 1190
1090 string assembly = ""; 1191 string assembly = "";
1091 1192
1092 CultureInfo USCulture = new CultureInfo("en-US"); 1193 Culture.SetCurrentCulture();
1093 Thread.CurrentThread.CurrentCulture = USCulture;
1094 1194
1095 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; 1195 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1096 1196
@@ -1256,12 +1356,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1256 m_DomainScripts[appDomain].Add(itemID); 1356 m_DomainScripts[appDomain].Add(itemID);
1257 1357
1258 instance = new ScriptInstance(this, part, 1358 instance = new ScriptInstance(this, part,
1259 itemID, assetID, assembly, 1359 item,
1260 m_AppDomains[appDomain], 1360 startParam, postOnRez,
1261 part.ParentGroup.RootPart.Name, 1361 m_MaxScriptQueue);
1262 item.Name, startParam, postOnRez,
1263 stateSource, m_MaxScriptQueue);
1264 1362
1363 instance.Load(m_AppDomains[appDomain], assembly, stateSource);
1265// m_log.DebugFormat( 1364// m_log.DebugFormat(
1266// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", 1365// "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
1267// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, 1366// part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
@@ -1347,9 +1446,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1347 lockScriptsForWrite(false); 1446 lockScriptsForWrite(false);
1348 instance.ClearQueue(); 1447 instance.ClearQueue();
1349 1448
1350 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1449 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 1450
1354// bool objectRemoved = false; 1451// bool objectRemoved = false;
1355 1452
@@ -1485,6 +1582,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1485 startInfo.StartSuspended = true; 1582 startInfo.StartSuspended = true;
1486 1583
1487 m_ThreadPool = new SmartThreadPool(startInfo); 1584 m_ThreadPool = new SmartThreadPool(startInfo);
1585 m_ThreadPool.Name = "XEngine";
1488 } 1586 }
1489 1587
1490 // 1588 //
@@ -1504,8 +1602,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1504 /// <returns></returns> 1602 /// <returns></returns>
1505 private object ProcessEventHandler(object parms) 1603 private object ProcessEventHandler(object parms)
1506 { 1604 {
1507 CultureInfo USCulture = new CultureInfo("en-US"); 1605 Culture.SetCurrentCulture();
1508 Thread.CurrentThread.CurrentCulture = USCulture;
1509 1606
1510 IScriptInstance instance = (ScriptInstance) parms; 1607 IScriptInstance instance = (ScriptInstance) parms;
1511 1608
@@ -1693,7 +1790,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1693 { 1790 {
1694 IScriptInstance instance = GetInstance(itemID); 1791 IScriptInstance instance = GetInstance(itemID);
1695 if (instance != null) 1792 if (instance != null)
1696 instance.ResetScript(); 1793 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1697 } 1794 }
1698 1795
1699 public void StartScript(UUID itemID) 1796 public void StartScript(UUID itemID)
@@ -1708,14 +1805,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1708 public void StopScript(UUID itemID) 1805 public void StopScript(UUID itemID)
1709 { 1806 {
1710 IScriptInstance instance = GetInstance(itemID); 1807 IScriptInstance instance = GetInstance(itemID);
1808
1711 if (instance != null) 1809 if (instance != null)
1712 { 1810 {
1713 // Give the script some time to finish processing its last event. Simply aborting the script thread can 1811 instance.Stop(m_WaitForEventCompletionOnScriptStop);
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 } 1812 }
1717 else 1813 else
1718 { 1814 {
1815// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name);
1719 m_runFlags.AddOrUpdate(itemID, false, 240); 1816 m_runFlags.AddOrUpdate(itemID, false, 240);
1720 } 1817 }
1721 } 1818 }
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..2e6d279 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 }
@@ -118,8 +280,11 @@ namespace OpenSim.Server.Base
118 { 280 {
119 if (!(e is System.MissingMethodException)) 281 if (!(e is System.MissingMethodException))
120 { 282 {
121 m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}", 283 m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}",
122 interfaceName, dllName, e.InnerException == null ? e.Message : e.InnerException.Message); 284 interfaceName,
285 dllName,
286 e.InnerException == null ? e.Message : e.InnerException.Message,
287 e.StackTrace);
123 } 288 }
124 return null; 289 return null;
125 } 290 }
@@ -333,5 +498,42 @@ namespace OpenSim.Server.Base
333 498
334 return ret; 499 return ret;
335 } 500 }
501
502 public static IConfig GetConfig(string configFile, string configName)
503 {
504 IConfig config;
505
506 if (File.Exists(configFile))
507 {
508 IConfigSource configsource = new IniConfigSource(configFile);
509 config = configsource.Configs[configName];
510 }
511 else
512 config = null;
513
514 return config;
515 }
516
517 public static IConfigSource LoadInitialConfig(string url)
518 {
519 IConfigSource source = new XmlConfigSource();
520 m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url);
521
522 // The ini file path is a http URI
523 // Try to read it
524 try
525 {
526 XmlReader r = XmlReader.Create(url);
527 IConfigSource cs = new XmlConfigSource(r);
528 source.Merge(cs);
529 }
530 catch (Exception e)
531 {
532 m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url);
533 Environment.Exit(1);
534 }
535
536 return source;
537 }
336 } 538 }
337} 539}
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/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs
index ee3b858..daebf8b 100644
--- a/OpenSim/Services/GridService/GridService.cs
+++ b/OpenSim/Services/GridService/GridService.cs
@@ -185,15 +185,15 @@ namespace OpenSim.Services.GridService
185 185
186 if (!m_AllowDuplicateNames) 186 if (!m_AllowDuplicateNames)
187 { 187 {
188 List<RegionData> dupe = m_Database.Get(regionInfos.RegionName, scopeID); 188 List<RegionData> dupe = m_Database.Get(Util.EscapeForLike(regionInfos.RegionName), scopeID);
189 if (dupe != null && dupe.Count > 0) 189 if (dupe != null && dupe.Count > 0)
190 { 190 {
191 foreach (RegionData d in dupe) 191 foreach (RegionData d in dupe)
192 { 192 {
193 if (d.RegionID != regionInfos.RegionID) 193 if (d.RegionID != regionInfos.RegionID)
194 { 194 {
195 m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register duplicate name with ID {1}.", 195 m_log.WarnFormat("[GRID SERVICE]: Region tried to register using a duplicate name. New region: {0} ({1}), existing region: {2} ({3}).",
196 regionInfos.RegionName, regionInfos.RegionID); 196 regionInfos.RegionName, regionInfos.RegionID, d.RegionName, d.RegionID);
197 return "Duplicate region name"; 197 return "Duplicate region name";
198 } 198 }
199 } 199 }
@@ -359,7 +359,7 @@ namespace OpenSim.Services.GridService
359 359
360 public GridRegion GetRegionByName(UUID scopeID, string name) 360 public GridRegion GetRegionByName(UUID scopeID, string name)
361 { 361 {
362 List<RegionData> rdatas = m_Database.Get(name, scopeID); 362 List<RegionData> rdatas = m_Database.Get(Util.EscapeForLike(name), scopeID);
363 if ((rdatas != null) && (rdatas.Count > 0)) 363 if ((rdatas != null) && (rdatas.Count > 0))
364 return RegionData2RegionInfo(rdatas[0]); // get the first 364 return RegionData2RegionInfo(rdatas[0]); // get the first
365 365
@@ -377,7 +377,7 @@ namespace OpenSim.Services.GridService
377 { 377 {
378// m_log.DebugFormat("[GRID SERVICE]: GetRegionsByName {0}", name); 378// m_log.DebugFormat("[GRID SERVICE]: GetRegionsByName {0}", name);
379 379
380 List<RegionData> rdatas = m_Database.Get(name + "%", scopeID); 380 List<RegionData> rdatas = m_Database.Get(Util.EscapeForLike(name) + "%", scopeID);
381 381
382 int count = 0; 382 int count = 0;
383 List<GridRegion> rinfos = new List<GridRegion>(); 383 List<GridRegion> rinfos = new List<GridRegion>();
@@ -586,7 +586,7 @@ namespace OpenSim.Services.GridService
586 586
587 string regionName = cmd[3]; 587 string regionName = cmd[3];
588 588
589 List<RegionData> regions = m_Database.Get(regionName, UUID.Zero); 589 List<RegionData> regions = m_Database.Get(Util.EscapeForLike(regionName), UUID.Zero);
590 if (regions == null || regions.Count < 1) 590 if (regions == null || regions.Count < 1)
591 { 591 {
592 MainConsole.Instance.Output("No region with name {0} found", regionName); 592 MainConsole.Instance.Output("No region with name {0} found", regionName);
@@ -716,7 +716,7 @@ namespace OpenSim.Services.GridService
716 return; 716 return;
717 } 717 }
718 718
719 List<RegionData> regions = m_Database.Get(cmd[3], UUID.Zero); 719 List<RegionData> regions = m_Database.Get(Util.EscapeForLike(cmd[3]), UUID.Zero);
720 if (regions == null || regions.Count < 1) 720 if (regions == null || regions.Count < 1)
721 { 721 {
722 MainConsole.Instance.Output("Region not found"); 722 MainConsole.Instance.Output("Region not found");
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs
index 743d089..073197f 100644
--- a/OpenSim/Services/GridService/HypergridLinker.cs
+++ b/OpenSim/Services/GridService/HypergridLinker.cs
@@ -387,7 +387,7 @@ namespace OpenSim.Services.GridService
387 m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName); 387 m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName);
388 GridRegion regInfo = null; 388 GridRegion regInfo = null;
389 389
390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); 390 List<RegionData> regions = m_Database.Get(Util.EscapeForLike(mapName), m_ScopeID);
391 if (regions != null && regions.Count > 0) 391 if (regions != null && regions.Count > 0)
392 { 392 {
393 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); 393 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
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/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs
index 00faa44..7bad4b0 100644
--- a/OpenSim/Services/InventoryService/XInventoryService.cs
+++ b/OpenSim/Services/InventoryService/XInventoryService.cs
@@ -219,9 +219,15 @@ namespace OpenSim.Services.InventoryService
219 219
220 XInventoryFolder root = null; 220 XInventoryFolder root = null;
221 foreach (XInventoryFolder folder in folders) 221 foreach (XInventoryFolder folder in folders)
222 {
222 if (folder.folderName == "My Inventory") 223 if (folder.folderName == "My Inventory")
224 {
223 root = folder; 225 root = folder;
224 if (folders == null) // oops 226 break;
227 }
228 }
229
230 if (root == null) // oops
225 root = folders[0]; 231 root = folders[0];
226 232
227 return ConvertToOpenSim(root); 233 return ConvertToOpenSim(root);
@@ -249,6 +255,9 @@ namespace OpenSim.Services.InventoryService
249 { 255 {
250// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID); 256// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID);
251 257
258 if (type == AssetType.RootFolder)
259 return rootFolder;
260
252 XInventoryFolder[] folders = m_Database.GetFolders( 261 XInventoryFolder[] folders = m_Database.GetFolders(
253 new string[] { "agentID", "parentFolderID", "type"}, 262 new string[] { "agentID", "parentFolderID", "type"},
254 new string[] { rootFolder.Owner.ToString(), rootFolder.ID.ToString(), ((int)type).ToString() }); 263 new string[] { rootFolder.Owner.ToString(), rootFolder.ID.ToString(), ((int)type).ToString() });
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 afda574..fde1b91 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/TESTING.txt b/TESTING.txt
index 08a0698..a7346ff 100644
--- a/TESTING.txt
+++ b/TESTING.txt
@@ -1,4 +1,4 @@
1=== The Quick Guide to OpenSim Unit Testing === 1===== The Quick Guide to OpenSim Unit Testing ===
2 2
3== Running Tests == 3== Running Tests ==
4 4
diff --git a/ThirdPartyLicenses/Bullet-XNA.txt b/ThirdPartyLicenses/Bullet-XNA.txt
new file mode 100644
index 0000000..5d8899b
--- /dev/null
+++ b/ThirdPartyLicenses/Bullet-XNA.txt
@@ -0,0 +1,23 @@
1/*
2 * C# / XNA port of Bullet (c) 2011 Mark Neale <xexuxjy@hotmail.com>
3 * http://code.google.com/p/bullet-xna/
4 *
5 * Bullet Continuous Collision Detection and Physics Library
6 * Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
7 *
8 * This software is provided 'as-is', without any express or implied warranty.
9 * In no event will the authors be held liable for any damages arising from
10 * the use of this software.
11 *
12 * Permission is granted to anyone to use this software for any purpose,
13 * including commercial applications, and to alter it and redistribute it
14 * freely, subject to the following restrictions:
15 *
16 * 1. The origin of this software must not be misrepresented; you must not
17 * claim that you wrote the original software. If you use this software
18 * in a product, an acknowledgment in the product documentation would be
19 * appreciated but is not required.
20 * 2. Altered source versions must be plainly marked as such, and must not be
21 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source distribution.
23 */ \ No newline at end of file
diff --git a/bin/BulletXNA.dll b/bin/BulletXNA.dll
new file mode 100644
index 0000000..1e3f042
--- /dev/null
+++ b/bin/BulletXNA.dll
Binary files differ
diff --git a/bin/BulletXNA.pdb b/bin/BulletXNA.pdb
new file mode 100644
index 0000000..4b83b83
--- /dev/null
+++ b/bin/BulletXNA.pdb
Binary files differ
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/OpenSim.ini.example b/bin/OpenSim.ini.example
index 6757081..cc750a9 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -206,12 +206,13 @@
206 ;; Choose one of the physics engines below 206 ;; Choose one of the physics engines below
207 ;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine 207 ;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine
208 ;; OpenDynamicsEngine is by some distance the most developed physics engine 208 ;; OpenDynamicsEngine is by some distance the most developed physics engine
209 ;; BulletSim is incomplete and experimental but in active development 209 ;; BulletSim is incomplete and experimental but in active development. BulletSimN is a purely C# version of BulletSim.
210 ;; basicphysics effectively does not model physics at all, making all 210 ;; basicphysics effectively does not model physics at all, making all
211 ;; objects phantom 211 ;; objects phantom.
212 ;; Default is OpenDynamicsEngine 212 ;; Default is OpenDynamicsEngine
213 ; physics = OpenDynamicsEngine 213 ; physics = OpenDynamicsEngine
214 ; physics = BulletSim 214 ; physics = BulletSim
215 ; physics = BulletSimN
215 ; physics = basicphysics 216 ; physics = basicphysics
216 ; physics = POS 217 ; physics = POS
217 218
@@ -786,8 +787,9 @@
786 ;; Allow the use of os* functions (some are dangerous) 787 ;; Allow the use of os* functions (some are dangerous)
787 ; AllowOSFunctions = false 788 ; AllowOSFunctions = false
788 789
789 ;# {AllowLightShareFunctions} {Enabled:true [LightShare]enable_windlight:true} {Allow LightShare functions?} {true false} true 790 ;# {AllowLightShareFunctions} {Enabled:false [LightShare]enable_windlight:true} {Allow LightShare functions?} {true false} false
790 ; Allow the user of LightShare functions 791 ; Allow the use of LightShare functions.
792 ; The setting enable_windlight = true must also be enabled in the [LightShare] section.
791 ; AllowLightShareFunctions = false 793 ; AllowLightShareFunctions = false
792 794
793 ;# {OSFunctionThreatLevel} {Enabled:true AllowOSFunctions:true} {OSFunction threat level? (DANGEROUS!)} {None VeryLow Low Moderate High VeryHigh Severe} VeryLow 795 ;# {OSFunctionThreatLevel} {Enabled:true AllowOSFunctions:true} {OSFunction threat level? (DANGEROUS!)} {None VeryLow Low Moderate High VeryHigh Severe} VeryLow
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 54f252e..85f7708 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,17 +904,20 @@
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 = 10.0
910 AvatarRestitution = 0.0 919 AvatarRestitution = 0.0
911 AvatarDensity = 60.0 920 AvatarDensity = 3.5
912 AvatarCapsuleWidth = 0.6 921 AvatarCapsuleWidth = 0.6
913 AvatarCapsuleDepth = 0.45 922 AvatarCapsuleDepth = 0.45
914 AvatarCapsuleHeight = 1.5 923 AvatarCapsuleHeight = 1.5
@@ -916,30 +925,10 @@
916 925
917 MaxObjectMass = 10000.01 926 MaxObjectMass = 10000.01
918 927
919 ; Dynamic parameters 928 CollisionMargin = 0.04
920 LinearDamping = 0.0
921 AngularDamping = 0.0
922 DeactivationTime = 0.2
923 LinearSleepingThreshold = 0.8
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 929
937 ; Linkset constraint parameters 930 ; Linkset constraint parameters
938 LinkConstraintUseFrameOffset = False 931 LinkImplementation = 1 ; 0=constraint, 1=compound
939 LinkConstraintEnableTransMotor = True
940 LinkConstraintTransMotorMaxVel = 5.0
941 LinkConstraintTransMotorMaxForce = 0.1
942
943 932
944 ; Whether to mesh sculpties 933 ; Whether to mesh sculpties
945 MeshSculptedPrim = true 934 MeshSculptedPrim = true
@@ -1367,6 +1356,10 @@
1367 ; If a script overruns it's event limit, kill the script? 1356 ; If a script overruns it's event limit, kill the script?
1368 KillTimedOutScripts = false 1357 KillTimedOutScripts = false
1369 1358
1359 ; Amount of time in milliseconds we will wait for an event to completely normally when a script stop is requested
1360 ; before aborting the thread (such as when an object containing scripts is taken into inventory).
1361 WaitForEventCompletionOnScriptStop = 1000;
1362
1370 ; Sets the multiplier for the scripting delays 1363 ; Sets the multiplier for the scripting delays
1371 ScriptDelayFactor = 1.0 1364 ScriptDelayFactor = 1.0
1372 1365
@@ -1582,8 +1575,7 @@
1582 1575
1583 ; If true, then the basic packet objects used to receive data are also recycled, not just the LLUDP packets. 1576 ; If true, then the basic packet objects used to receive data are also recycled, not just the LLUDP packets.
1584 ; This reduces data churn 1577 ; This reduces data churn
1585 ; This setting is currently experimental and defaults to false. 1578 RecycleBaseUDPPackets = true
1586 RecycleBaseUDPPackets = false;
1587 1579
1588 1580
1589[InterestManagement] 1581[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..014eca4 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..5e4d8cc 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..d00549e 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..b94e264 100755
--- a/bin/lib64/libBulletSim.so
+++ b/bin/lib64/libBulletSim.so
Binary files differ
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..9c95557
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,20 @@
1README
2
3This directory does not currently contain any OpenSimulator user level documentation. Such
4documentation can be found at
5
6http://opensimulator.org
7
8instead.
9
10Rather, this directory can contain source-code documentation as generated via the doxygen package.
11
12To do this, either execute
13
14doxygen doxygen.conf
15
16on the command line or run the target
17
18nant doxygen
19
20if you have nant installed.
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
index 3712dfa..148de9c 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf
@@ -1,1356 +1,290 @@
1# Doxyfile 1.5.5 1# Doxyfile 1.8.2
2
3# This file describes the settings to be used by the documentation system
4# doxygen (www.doxygen.org) for a project
5#
6# All text after a hash (#) is considered a comment and will be ignored
7# The format is:
8# TAG = value [value, ...]
9# For lists items can also be appended using:
10# TAG += value [value, ...]
11# Values that contain spaces should be placed between quotes (" ")
12 2
13#--------------------------------------------------------------------------- 3#---------------------------------------------------------------------------
14# Project related configuration options 4# Project related configuration options
15#--------------------------------------------------------------------------- 5#---------------------------------------------------------------------------
16
17# This tag specifies the encoding used for all characters in the config file
18# that follow. The default is UTF-8 which is also the encoding used for all
19# text before the first occurrence of this tag. Doxygen uses libiconv (or the
20# iconv built into libc) for the transcoding. See
21# http://www.gnu.org/software/libiconv for the list of possible encodings.
22
23DOXYFILE_ENCODING = UTF-8 6DOXYFILE_ENCODING = UTF-8
24
25# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
26# by quotes) that should identify the project.
27
28PROJECT_NAME = OpenSim 7PROJECT_NAME = OpenSim
29 8PROJECT_NUMBER = GIT
30# The PROJECT_NUMBER tag can be used to enter a project or revision number. 9PROJECT_BRIEF =
31# This could be handy for archiving the generated documentation or 10PROJECT_LOGO =
32# if some version control system is used.
33
34PROJECT_NUMBER = SVN
35
36# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
37# base path where the generated documentation will be put.
38# If a relative path is entered, it will be relative to the location
39# where doxygen was started. If left blank the current directory will be used.
40
41OUTPUT_DIRECTORY = 11OUTPUT_DIRECTORY =
42
43# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
44# 4096 sub-directories (in 2 levels) under the output directory of each output
45# format and will distribute the generated files over these directories.
46# Enabling this option can be useful when feeding doxygen a huge amount of
47# source files, where putting all generated files in the same directory would
48# otherwise cause performance problems for the file system.
49
50CREATE_SUBDIRS = NO 12CREATE_SUBDIRS = NO
51
52# The OUTPUT_LANGUAGE tag is used to specify the language in which all
53# documentation generated by doxygen is written. Doxygen will use this
54# information to generate all constant output in the proper language.
55# The default language is English, other supported languages are:
56# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
57# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
58# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
59# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
60# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
61# and Ukrainian.
62
63OUTPUT_LANGUAGE = English 13OUTPUT_LANGUAGE = English
64
65# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
66# include brief member descriptions after the members that are listed in
67# the file and class documentation (similar to JavaDoc).
68# Set to NO to disable this.
69
70BRIEF_MEMBER_DESC = YES 14BRIEF_MEMBER_DESC = YES
71
72# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
73# the brief description of a member or function before the detailed description.
74# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
75# brief descriptions will be completely suppressed.
76
77REPEAT_BRIEF = YES 15REPEAT_BRIEF = YES
78 16ABBREVIATE_BRIEF =
79# This tag implements a quasi-intelligent brief description abbreviator
80# that is used to form the text in various listings. Each string
81# in this list, if found as the leading text of the brief description, will be
82# stripped from the text and the result after processing the whole list, is
83# used as the annotated text. Otherwise, the brief description is used as-is.
84# If left blank, the following values are used ("$name" is automatically
85# replaced with the name of the entity): "The $name class" "The $name widget"
86# "The $name file" "is" "provides" "specifies" "contains"
87# "represents" "a" "an" "the"
88
89ABBREVIATE_BRIEF =
90
91# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
92# Doxygen will generate a detailed section even if there is only a brief
93# description.
94
95ALWAYS_DETAILED_SEC = NO 17ALWAYS_DETAILED_SEC = NO
96
97# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
98# inherited members of a class in the documentation of that class as if those
99# members were ordinary class members. Constructors, destructors and assignment
100# operators of the base classes will not be shown.
101
102INLINE_INHERITED_MEMB = NO 18INLINE_INHERITED_MEMB = NO
103
104# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
105# path before files name in the file list and in the header files. If set
106# to NO the shortest path that makes the file name unique will be used.
107
108FULL_PATH_NAMES = YES 19FULL_PATH_NAMES = YES
109 20STRIP_FROM_PATH =
110# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 21STRIP_FROM_INC_PATH =
111# can be used to strip a user-defined part of the path. Stripping is
112# only done if one of the specified strings matches the left-hand part of
113# the path. The tag can be used to show relative paths in the file list.
114# If left blank the directory from which doxygen is run is used as the
115# path to strip.
116
117STRIP_FROM_PATH =
118
119# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
120# the path mentioned in the documentation of a class, which tells
121# the reader which header file to include in order to use a class.
122# If left blank only the name of the header file containing the class
123# definition is used. Otherwise one should specify the include paths that
124# are normally passed to the compiler using the -I flag.
125
126STRIP_FROM_INC_PATH =
127
128# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
129# (but less readable) file names. This can be useful is your file systems
130# doesn't support long names like on DOS, Mac, or CD-ROM.
131
132SHORT_NAMES = NO 22SHORT_NAMES = NO
133
134# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
135# will interpret the first line (until the first dot) of a JavaDoc-style
136# comment as the brief description. If set to NO, the JavaDoc
137# comments will behave just like regular Qt-style comments
138# (thus requiring an explicit @brief command for a brief description.)
139
140JAVADOC_AUTOBRIEF = NO 23JAVADOC_AUTOBRIEF = NO
141
142# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
143# interpret the first line (until the first dot) of a Qt-style
144# comment as the brief description. If set to NO, the comments
145# will behave just like regular Qt-style comments (thus requiring
146# an explicit \brief command for a brief description.)
147
148QT_AUTOBRIEF = NO 24QT_AUTOBRIEF = NO
149
150# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
151# treat a multi-line C++ special comment block (i.e. a block of //! or ///
152# comments) as a brief description. This used to be the default behaviour.
153# The new default is to treat a multi-line C++ comment block as a detailed
154# description. Set this tag to YES if you prefer the old behaviour instead.
155
156MULTILINE_CPP_IS_BRIEF = NO 25MULTILINE_CPP_IS_BRIEF = NO
157
158# If the DETAILS_AT_TOP tag is set to YES then Doxygen
159# will output the detailed description near the top, like JavaDoc.
160# If set to NO, the detailed description appears after the member
161# documentation.
162
163DETAILS_AT_TOP = NO
164
165# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
166# member inherits the documentation from any documented member that it
167# re-implements.
168
169INHERIT_DOCS = YES 26INHERIT_DOCS = YES
170
171# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
172# a new page for each member. If set to NO, the documentation of a member will
173# be part of the file/class/namespace that contains it.
174
175SEPARATE_MEMBER_PAGES = NO 27SEPARATE_MEMBER_PAGES = NO
176
177# The TAB_SIZE tag can be used to set the number of spaces in a tab.
178# Doxygen uses this value to replace tabs by spaces in code fragments.
179
180TAB_SIZE = 8 28TAB_SIZE = 8
181 29ALIASES =
182# This tag can be used to specify a number of aliases that acts 30TCL_SUBST =
183# as commands in the documentation. An alias has the form "name=value".
184# For example adding "sideeffect=\par Side Effects:\n" will allow you to
185# put the command \sideeffect (or @sideeffect) in the documentation, which
186# will result in a user-defined paragraph with heading "Side Effects:".
187# You can put \n's in the value part of an alias to insert newlines.
188
189ALIASES =
190
191# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
192# sources only. Doxygen will then generate output that is more tailored for C.
193# For instance, some of the names that are used will be different. The list
194# of all members will be omitted, etc.
195
196OPTIMIZE_OUTPUT_FOR_C = NO 31OPTIMIZE_OUTPUT_FOR_C = NO
197
198# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
199# sources only. Doxygen will then generate output that is more tailored for
200# Java. For instance, namespaces will be presented as packages, qualified
201# scopes will look different, etc.
202
203OPTIMIZE_OUTPUT_JAVA = NO 32OPTIMIZE_OUTPUT_JAVA = NO
204
205# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
206# sources only. Doxygen will then generate output that is more tailored for
207# Fortran.
208
209OPTIMIZE_FOR_FORTRAN = NO 33OPTIMIZE_FOR_FORTRAN = NO
210
211# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
212# sources. Doxygen will then generate output that is tailored for
213# VHDL.
214
215OPTIMIZE_OUTPUT_VHDL = NO 34OPTIMIZE_OUTPUT_VHDL = NO
216 35EXTENSION_MAPPING =
217# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 36MARKDOWN_SUPPORT = YES
218# to include (a tag file for) the STL sources as input, then you should 37AUTOLINK_SUPPORT = YES
219# set this tag to YES in order to let doxygen match functions declarations and
220# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
221# func(std::string) {}). This also make the inheritance and collaboration
222# diagrams that involve STL classes more complete and accurate.
223
224BUILTIN_STL_SUPPORT = NO 38BUILTIN_STL_SUPPORT = NO
225
226# If you use Microsoft's C++/CLI language, you should set this option to YES to
227# enable parsing support.
228
229CPP_CLI_SUPPORT = NO 39CPP_CLI_SUPPORT = NO
230
231# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
232# Doxygen will parse them like normal C++ but will assume all classes use public
233# instead of private inheritance when no explicit protection keyword is present.
234
235SIP_SUPPORT = NO 40SIP_SUPPORT = NO
236 41IDL_PROPERTY_SUPPORT = YES
237# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
238# tag is set to YES, then doxygen will reuse the documentation of the first
239# member in the group (if any) for the other members of the group. By default
240# all members of a group must be documented explicitly.
241
242DISTRIBUTE_GROUP_DOC = NO 42DISTRIBUTE_GROUP_DOC = NO
243
244# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
245# the same type (for instance a group of public functions) to be put as a
246# subgroup of that type (e.g. under the Public Functions section). Set it to
247# NO to prevent subgrouping. Alternatively, this can be done per class using
248# the \nosubgrouping command.
249
250SUBGROUPING = YES 43SUBGROUPING = YES
251 44INLINE_GROUPED_CLASSES = NO
252# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 45INLINE_SIMPLE_STRUCTS = NO
253# is documented as struct, union, or enum with the name of the typedef. So
254# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
255# with name TypeT. When disabled the typedef will appear as a member of a file,
256# namespace, or class. And the struct will be named TypeS. This can typically
257# be useful for C code in case the coding convention dictates that all compound
258# types are typedef'ed and only the typedef is referenced, never the tag name.
259
260TYPEDEF_HIDES_STRUCT = NO 46TYPEDEF_HIDES_STRUCT = NO
261 47SYMBOL_CACHE_SIZE = 0
48LOOKUP_CACHE_SIZE = 0
262#--------------------------------------------------------------------------- 49#---------------------------------------------------------------------------
263# Build related configuration options 50# Build related configuration options
264#--------------------------------------------------------------------------- 51#---------------------------------------------------------------------------
265
266# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
267# documentation are documented, even if no documentation was available.
268# Private class members and static file members will be hidden unless
269# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
270
271EXTRACT_ALL = YES 52EXTRACT_ALL = YES
272
273# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
274# will be included in the documentation.
275
276EXTRACT_PRIVATE = NO 53EXTRACT_PRIVATE = NO
277 54EXTRACT_PACKAGE = NO
278# If the EXTRACT_STATIC tag is set to YES all static members of a file
279# will be included in the documentation.
280
281EXTRACT_STATIC = NO 55EXTRACT_STATIC = NO
282
283# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
284# defined locally in source files will be included in the documentation.
285# If set to NO only classes defined in header files are included.
286
287EXTRACT_LOCAL_CLASSES = YES 56EXTRACT_LOCAL_CLASSES = YES
288
289# This flag is only useful for Objective-C code. When set to YES local
290# methods, which are defined in the implementation section but not in
291# the interface are included in the documentation.
292# If set to NO (the default) only methods in the interface are included.
293
294EXTRACT_LOCAL_METHODS = NO 57EXTRACT_LOCAL_METHODS = NO
295
296# If this flag is set to YES, the members of anonymous namespaces will be
297# extracted and appear in the documentation as a namespace called
298# 'anonymous_namespace{file}', where file will be replaced with the base
299# name of the file that contains the anonymous namespace. By default
300# anonymous namespace are hidden.
301
302EXTRACT_ANON_NSPACES = NO 58EXTRACT_ANON_NSPACES = NO
303
304# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
305# undocumented members of documented classes, files or namespaces.
306# If set to NO (the default) these members will be included in the
307# various overviews, but no documentation section is generated.
308# This option has no effect if EXTRACT_ALL is enabled.
309
310HIDE_UNDOC_MEMBERS = NO 59HIDE_UNDOC_MEMBERS = NO
311
312# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
313# undocumented classes that are normally visible in the class hierarchy.
314# If set to NO (the default) these classes will be included in the various
315# overviews. This option has no effect if EXTRACT_ALL is enabled.
316
317HIDE_UNDOC_CLASSES = NO 60HIDE_UNDOC_CLASSES = NO
318
319# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
320# friend (class|struct|union) declarations.
321# If set to NO (the default) these declarations will be included in the
322# documentation.
323
324HIDE_FRIEND_COMPOUNDS = NO 61HIDE_FRIEND_COMPOUNDS = NO
325
326# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
327# documentation blocks found inside the body of a function.
328# If set to NO (the default) these blocks will be appended to the
329# function's detailed documentation block.
330
331HIDE_IN_BODY_DOCS = NO 62HIDE_IN_BODY_DOCS = NO
332
333# The INTERNAL_DOCS tag determines if documentation
334# that is typed after a \internal command is included. If the tag is set
335# to NO (the default) then the documentation will be excluded.
336# Set it to YES to include the internal documentation.
337
338INTERNAL_DOCS = NO 63INTERNAL_DOCS = NO
339
340# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
341# file names in lower-case letters. If set to YES upper-case letters are also
342# allowed. This is useful if you have classes or files whose names only differ
343# in case and if your file system supports case sensitive file names. Windows
344# and Mac users are advised to set this option to NO.
345
346CASE_SENSE_NAMES = YES 64CASE_SENSE_NAMES = YES
347
348# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
349# will show members with their full class and namespace scopes in the
350# documentation. If set to YES the scope will be hidden.
351
352HIDE_SCOPE_NAMES = NO 65HIDE_SCOPE_NAMES = NO
353
354# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
355# will put a list of the files that are included by a file in the documentation
356# of that file.
357
358SHOW_INCLUDE_FILES = YES 66SHOW_INCLUDE_FILES = YES
359 67FORCE_LOCAL_INCLUDES = NO
360# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
361# is inserted in the documentation for inline members.
362
363INLINE_INFO = YES 68INLINE_INFO = YES
364
365# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
366# will sort the (detailed) documentation of file and class members
367# alphabetically by member name. If set to NO the members will appear in
368# declaration order.
369
370SORT_MEMBER_DOCS = YES 69SORT_MEMBER_DOCS = YES
371
372# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
373# brief documentation of file, namespace and class members alphabetically
374# by member name. If set to NO (the default) the members will appear in
375# declaration order.
376
377SORT_BRIEF_DOCS = NO 70SORT_BRIEF_DOCS = NO
378 71SORT_MEMBERS_CTORS_1ST = NO
379# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
380# hierarchy of group names into alphabetical order. If set to NO (the default)
381# the group names will appear in their defined order.
382
383SORT_GROUP_NAMES = NO 72SORT_GROUP_NAMES = NO
384
385# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
386# sorted by fully-qualified names, including namespaces. If set to
387# NO (the default), the class list will be sorted only by class name,
388# not including the namespace part.
389# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
390# Note: This option applies only to the class list, not to the
391# alphabetical list.
392
393SORT_BY_SCOPE_NAME = NO 73SORT_BY_SCOPE_NAME = NO
394 74STRICT_PROTO_MATCHING = NO
395# The GENERATE_TODOLIST tag can be used to enable (YES) or
396# disable (NO) the todo list. This list is created by putting \todo
397# commands in the documentation.
398
399GENERATE_TODOLIST = YES 75GENERATE_TODOLIST = YES
400
401# The GENERATE_TESTLIST tag can be used to enable (YES) or
402# disable (NO) the test list. This list is created by putting \test
403# commands in the documentation.
404
405GENERATE_TESTLIST = YES 76GENERATE_TESTLIST = YES
406
407# The GENERATE_BUGLIST tag can be used to enable (YES) or
408# disable (NO) the bug list. This list is created by putting \bug
409# commands in the documentation.
410
411GENERATE_BUGLIST = YES 77GENERATE_BUGLIST = YES
412
413# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
414# disable (NO) the deprecated list. This list is created by putting
415# \deprecated commands in the documentation.
416
417GENERATE_DEPRECATEDLIST= YES 78GENERATE_DEPRECATEDLIST= YES
418 79ENABLED_SECTIONS =
419# The ENABLED_SECTIONS tag can be used to enable conditional
420# documentation sections, marked by \if sectionname ... \endif.
421
422ENABLED_SECTIONS =
423
424# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
425# the initial value of a variable or define consists of for it to appear in
426# the documentation. If the initializer consists of more lines than specified
427# here it will be hidden. Use a value of 0 to hide initializers completely.
428# The appearance of the initializer of individual variables and defines in the
429# documentation can be controlled using \showinitializer or \hideinitializer
430# command in the documentation regardless of this setting.
431
432MAX_INITIALIZER_LINES = 30 80MAX_INITIALIZER_LINES = 30
433
434# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
435# at the bottom of the documentation of classes and structs. If set to YES the
436# list will mention the files that were used to generate the documentation.
437
438SHOW_USED_FILES = YES 81SHOW_USED_FILES = YES
439 82SHOW_FILES = YES
440# If the sources in your project are distributed over multiple directories 83SHOW_NAMESPACES = YES
441# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 84FILE_VERSION_FILTER =
442# in the documentation. The default is NO. 85LAYOUT_FILE =
443 86CITE_BIB_FILES =
444SHOW_DIRECTORIES = NO
445
446# The FILE_VERSION_FILTER tag can be used to specify a program or script that
447# doxygen should invoke to get the current version for each file (typically from
448# the version control system). Doxygen will invoke the program by executing (via
449# popen()) the command <command> <input-file>, where <command> is the value of
450# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
451# provided by doxygen. Whatever the program writes to standard output
452# is used as the file version. See the manual for examples.
453
454FILE_VERSION_FILTER =
455
456#--------------------------------------------------------------------------- 87#---------------------------------------------------------------------------
457# configuration options related to warning and progress messages 88# configuration options related to warning and progress messages
458#--------------------------------------------------------------------------- 89#---------------------------------------------------------------------------
459
460# The QUIET tag can be used to turn on/off the messages that are generated
461# by doxygen. Possible values are YES and NO. If left blank NO is used.
462
463QUIET = NO 90QUIET = NO
464
465# The WARNINGS tag can be used to turn on/off the warning messages that are
466# generated by doxygen. Possible values are YES and NO. If left blank
467# NO is used.
468
469WARNINGS = YES 91WARNINGS = YES
470
471# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
472# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
473# automatically be disabled.
474
475WARN_IF_UNDOCUMENTED = YES 92WARN_IF_UNDOCUMENTED = YES
476
477# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
478# potential errors in the documentation, such as not documenting some
479# parameters in a documented function, or documenting parameters that
480# don't exist or using markup commands wrongly.
481
482WARN_IF_DOC_ERROR = YES 93WARN_IF_DOC_ERROR = YES
483
484# This WARN_NO_PARAMDOC option can be abled to get warnings for
485# functions that are documented, but have no documentation for their parameters
486# or return value. If set to NO (the default) doxygen will only warn about
487# wrong or incomplete parameter documentation, but not about the absence of
488# documentation.
489
490WARN_NO_PARAMDOC = NO 94WARN_NO_PARAMDOC = NO
491
492# The WARN_FORMAT tag determines the format of the warning messages that
493# doxygen can produce. The string should contain the $file, $line, and $text
494# tags, which will be replaced by the file and line number from which the
495# warning originated and the warning text. Optionally the format may contain
496# $version, which will be replaced by the version of the file (if it could
497# be obtained via FILE_VERSION_FILTER)
498
499WARN_FORMAT = "$file:$line: $text" 95WARN_FORMAT = "$file:$line: $text"
500 96WARN_LOGFILE = doxygen.error.log
501# The WARN_LOGFILE tag can be used to specify a file to which warning
502# and error messages should be written. If left blank the output is written
503# to stderr.
504
505WARN_LOGFILE =
506
507#--------------------------------------------------------------------------- 97#---------------------------------------------------------------------------
508# configuration options related to the input files 98# configuration options related to the input files
509#--------------------------------------------------------------------------- 99#---------------------------------------------------------------------------
510
511# The INPUT tag can be used to specify the files and/or directories that contain
512# documented source files. You may enter file names like "myfile.cpp" or
513# directories like "/usr/src/myproject". Separate the files or directories
514# with spaces.
515
516INPUT = ../OpenSim 100INPUT = ../OpenSim
517
518# This tag can be used to specify the character encoding of the source files
519# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
520# also the default input encoding. Doxygen uses libiconv (or the iconv built
521# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
522# the list of possible encodings.
523
524INPUT_ENCODING = UTF-8 101INPUT_ENCODING = UTF-8
525 102FILE_PATTERNS =
526# If the value of the INPUT tag contains directories, you can use the
527# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
528# and *.h) to filter out the source-files in the directories. If left
529# blank the following patterns are tested:
530# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
531# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
532
533FILE_PATTERNS =
534
535# The RECURSIVE tag can be used to turn specify whether or not subdirectories
536# should be searched for input files as well. Possible values are YES and NO.
537# If left blank NO is used.
538
539RECURSIVE = YES 103RECURSIVE = YES
540
541# The EXCLUDE tag can be used to specify files and/or directories that should
542# excluded from the INPUT source files. This way you can easily exclude a
543# subdirectory from a directory tree whose root is specified with the INPUT tag.
544
545EXCLUDE = 104EXCLUDE =
546
547# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
548# directories that are symbolic links (a Unix filesystem feature) are excluded
549# from the input.
550
551EXCLUDE_SYMLINKS = NO 105EXCLUDE_SYMLINKS = NO
552 106EXCLUDE_PATTERNS =
553# If the value of the INPUT tag contains directories, you can use the 107EXCLUDE_SYMBOLS =
554# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 108EXAMPLE_PATH =
555# certain files from those directories. Note that the wildcards are matched 109EXAMPLE_PATTERNS =
556# against the file with absolute path, so to exclude all test directories
557# for example use the pattern */test/*
558
559EXCLUDE_PATTERNS =
560
561# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
562# (namespaces, classes, functions, etc.) that should be excluded from the
563# output. The symbol name can be a fully qualified name, a word, or if the
564# wildcard * is used, a substring. Examples: ANamespace, AClass,
565# AClass::ANamespace, ANamespace::*Test
566
567EXCLUDE_SYMBOLS =
568
569# The EXAMPLE_PATH tag can be used to specify one or more files or
570# directories that contain example code fragments that are included (see
571# the \include command).
572
573EXAMPLE_PATH =
574
575# If the value of the EXAMPLE_PATH tag contains directories, you can use the
576# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
577# and *.h) to filter out the source-files in the directories. If left
578# blank all files are included.
579
580EXAMPLE_PATTERNS =
581
582# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
583# searched for input files to be used with the \include or \dontinclude
584# commands irrespective of the value of the RECURSIVE tag.
585# Possible values are YES and NO. If left blank NO is used.
586
587EXAMPLE_RECURSIVE = NO 110EXAMPLE_RECURSIVE = NO
588 111IMAGE_PATH =
589# The IMAGE_PATH tag can be used to specify one or more files or 112INPUT_FILTER =
590# directories that contain image that are included in the documentation (see 113FILTER_PATTERNS =
591# the \image command).
592
593IMAGE_PATH =
594
595# The INPUT_FILTER tag can be used to specify a program that doxygen should
596# invoke to filter for each input file. Doxygen will invoke the filter program
597# by executing (via popen()) the command <filter> <input-file>, where <filter>
598# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
599# input file. Doxygen will then use the output that the filter program writes
600# to standard output. If FILTER_PATTERNS is specified, this tag will be
601# ignored.
602
603INPUT_FILTER =
604
605# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
606# basis. Doxygen will compare the file name with each pattern and apply the
607# filter if there is a match. The filters are a list of the form:
608# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
609# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
610# is applied to all files.
611
612FILTER_PATTERNS =
613
614# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
615# INPUT_FILTER) will be used to filter the input files when producing source
616# files to browse (i.e. when SOURCE_BROWSER is set to YES).
617
618FILTER_SOURCE_FILES = NO 114FILTER_SOURCE_FILES = NO
619 115FILTER_SOURCE_PATTERNS =
620#--------------------------------------------------------------------------- 116#---------------------------------------------------------------------------
621# configuration options related to source browsing 117# configuration options related to source browsing
622#--------------------------------------------------------------------------- 118#---------------------------------------------------------------------------
623
624# If the SOURCE_BROWSER tag is set to YES then a list of source files will
625# be generated. Documented entities will be cross-referenced with these sources.
626# Note: To get rid of all source code in the generated output, make sure also
627# VERBATIM_HEADERS is set to NO.
628
629SOURCE_BROWSER = NO 119SOURCE_BROWSER = NO
630
631# Setting the INLINE_SOURCES tag to YES will include the body
632# of functions and classes directly in the documentation.
633
634INLINE_SOURCES = NO 120INLINE_SOURCES = NO
635
636# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
637# doxygen to hide any special comment blocks from generated source code
638# fragments. Normal C and C++ comments will always remain visible.
639
640STRIP_CODE_COMMENTS = YES 121STRIP_CODE_COMMENTS = YES
641
642# If the REFERENCED_BY_RELATION tag is set to YES (the default)
643# then for each documented function all documented
644# functions referencing it will be listed.
645
646REFERENCED_BY_RELATION = NO 122REFERENCED_BY_RELATION = NO
647
648# If the REFERENCES_RELATION tag is set to YES (the default)
649# then for each documented function all documented entities
650# called/used by that function will be listed.
651
652REFERENCES_RELATION = NO 123REFERENCES_RELATION = NO
653
654# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
655# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
656# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
657# link to the source code. Otherwise they will link to the documentstion.
658
659REFERENCES_LINK_SOURCE = YES 124REFERENCES_LINK_SOURCE = YES
660
661# If the USE_HTAGS tag is set to YES then the references to source code
662# will point to the HTML generated by the htags(1) tool instead of doxygen
663# built-in source browser. The htags tool is part of GNU's global source
664# tagging system (see http://www.gnu.org/software/global/global.html). You
665# will need version 4.8.6 or higher.
666
667USE_HTAGS = NO 125USE_HTAGS = NO
668
669# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
670# will generate a verbatim copy of the header file for each class for
671# which an include is specified. Set to NO to disable this.
672
673VERBATIM_HEADERS = YES 126VERBATIM_HEADERS = YES
674
675#--------------------------------------------------------------------------- 127#---------------------------------------------------------------------------
676# configuration options related to the alphabetical class index 128# configuration options related to the alphabetical class index
677#--------------------------------------------------------------------------- 129#---------------------------------------------------------------------------
678
679# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
680# of all compounds will be generated. Enable this if the project
681# contains a lot of classes, structs, unions or interfaces.
682
683ALPHABETICAL_INDEX = NO 130ALPHABETICAL_INDEX = NO
684
685# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
686# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
687# in which this list will be split (can be a number in the range [1..20])
688
689COLS_IN_ALPHA_INDEX = 5 131COLS_IN_ALPHA_INDEX = 5
690 132IGNORE_PREFIX =
691# In case all classes in a project start with a common prefix, all
692# classes will be put under the same header in the alphabetical index.
693# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
694# should be ignored while generating the index headers.
695
696IGNORE_PREFIX =
697
698#--------------------------------------------------------------------------- 133#---------------------------------------------------------------------------
699# configuration options related to the HTML output 134# configuration options related to the HTML output
700#--------------------------------------------------------------------------- 135#---------------------------------------------------------------------------
701
702# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
703# generate HTML output.
704
705GENERATE_HTML = YES 136GENERATE_HTML = YES
706
707# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
708# If a relative path is entered the value of OUTPUT_DIRECTORY will be
709# put in front of it. If left blank `html' will be used as the default path.
710
711HTML_OUTPUT = html 137HTML_OUTPUT = html
712
713# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
714# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
715# doxygen will generate files with .html extension.
716
717HTML_FILE_EXTENSION = .html 138HTML_FILE_EXTENSION = .html
718 139HTML_HEADER =
719# The HTML_HEADER tag can be used to specify a personal HTML header for 140HTML_FOOTER =
720# each generated HTML page. If it is left blank doxygen will generate a 141HTML_STYLESHEET =
721# standard header. 142HTML_EXTRA_STYLESHEET =
722 143HTML_EXTRA_FILES =
723HTML_HEADER = 144HTML_COLORSTYLE_HUE = 220
724 145HTML_COLORSTYLE_SAT = 100
725# The HTML_FOOTER tag can be used to specify a personal HTML footer for 146HTML_COLORSTYLE_GAMMA = 80
726# each generated HTML page. If it is left blank doxygen will generate a 147HTML_TIMESTAMP = YES
727# standard footer.
728
729HTML_FOOTER =
730
731# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
732# style sheet that is used by each HTML page. It can be used to
733# fine-tune the look of the HTML output. If the tag is left blank doxygen
734# will generate a default style sheet. Note that doxygen will try to copy
735# the style sheet file to the HTML output directory, so don't put your own
736# stylesheet in the HTML output directory as well, or it will be erased!
737
738HTML_STYLESHEET =
739
740# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
741# files or namespaces will be aligned in HTML using tables. If set to
742# NO a bullet list will be used.
743
744HTML_ALIGN_MEMBERS = YES
745
746# If the GENERATE_HTMLHELP tag is set to YES, additional index files
747# will be generated that can be used as input for tools like the
748# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
749# of the generated HTML documentation.
750
751GENERATE_HTMLHELP = NO
752
753# If the GENERATE_DOCSET tag is set to YES, additional index files
754# will be generated that can be used as input for Apple's Xcode 3
755# integrated development environment, introduced with OSX 10.5 (Leopard).
756# To create a documentation set, doxygen will generate a Makefile in the
757# HTML output directory. Running make will produce the docset in that
758# directory and running "make install" will install the docset in
759# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
760# it at startup.
761
762GENERATE_DOCSET = NO
763
764# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
765# feed. A documentation feed provides an umbrella under which multiple
766# documentation sets from a single provider (such as a company or product suite)
767# can be grouped.
768
769DOCSET_FEEDNAME = "Doxygen generated docs"
770
771# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
772# should uniquely identify the documentation set bundle. This should be a
773# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
774# will append .docset to the name.
775
776DOCSET_BUNDLE_ID = org.doxygen.Project
777
778# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
779# documentation will contain sections that can be hidden and shown after the
780# page has loaded. For this to work a browser that supports
781# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
782# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
783
784HTML_DYNAMIC_SECTIONS = NO 148HTML_DYNAMIC_SECTIONS = NO
785 149HTML_INDEX_NUM_ENTRIES = 100
786# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 150GENERATE_DOCSET = NO
787# be used to specify the file name of the resulting .chm file. You 151DOCSET_FEEDNAME = "OpenSimulator docs"
788# can add a path in front of the file if the result should not be 152DOCSET_BUNDLE_ID = org.opensimulator.OpenSim
789# written to the html output directory. 153DOCSET_PUBLISHER_ID = org.opensimulator.OpenSim
790 154DOCSET_PUBLISHER_NAME = OpenSim
791CHM_FILE = 155GENERATE_HTMLHELP = NO
792 156CHM_FILE =
793# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 157HHC_LOCATION =
794# be used to specify the location (absolute path including file name) of
795# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
796# the HTML help compiler on the generated index.hhp.
797
798HHC_LOCATION =
799
800# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
801# controls if a separate .chi index file is generated (YES) or that
802# it should be included in the master .chm file (NO).
803
804GENERATE_CHI = NO 158GENERATE_CHI = NO
805 159CHM_INDEX_ENCODING =
806# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
807# controls whether a binary table of contents is generated (YES) or a
808# normal table of contents (NO) in the .chm file.
809
810BINARY_TOC = NO 160BINARY_TOC = NO
811
812# The TOC_EXPAND flag can be set to YES to add extra items for group members
813# to the contents of the HTML help documentation and to the tree view.
814
815TOC_EXPAND = NO 161TOC_EXPAND = NO
816 162GENERATE_QHP = NO
817# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 163QCH_FILE =
818# top of each HTML page. The value NO (the default) enables the index and 164QHP_NAMESPACE = org.opensimulator.OpenSim
819# the value YES disables it. 165QHP_VIRTUAL_FOLDER = doc
820 166QHP_CUST_FILTER_NAME =
167QHP_CUST_FILTER_ATTRS =
168QHP_SECT_FILTER_ATTRS =
169QHG_LOCATION =
170GENERATE_ECLIPSEHELP = NO
171ECLIPSE_DOC_ID = org.opensimulator.OpenSim
821DISABLE_INDEX = NO 172DISABLE_INDEX = NO
822
823# This tag can be used to set the number of enum values (range [1..20])
824# that doxygen will group on one line in the generated HTML documentation.
825
826ENUM_VALUES_PER_LINE = 4
827
828# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
829# generated containing a tree-like index structure (just like the one that
830# is generated for HTML Help). For this to work a browser that supports
831# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
832# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
833# probably better off using the HTML help feature.
834
835GENERATE_TREEVIEW = NO 173GENERATE_TREEVIEW = NO
836 174ENUM_VALUES_PER_LINE = 4
837# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
838# used to set the initial width (in pixels) of the frame in which the tree
839# is shown.
840
841TREEVIEW_WIDTH = 250 175TREEVIEW_WIDTH = 250
842 176EXT_LINKS_IN_WINDOW = NO
177FORMULA_FONTSIZE = 10
178FORMULA_TRANSPARENT = YES
179USE_MATHJAX = NO
180MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
181MATHJAX_EXTENSIONS =
182SEARCHENGINE = YES
183SERVER_BASED_SEARCH = NO
843#--------------------------------------------------------------------------- 184#---------------------------------------------------------------------------
844# configuration options related to the LaTeX output 185# configuration options related to the LaTeX output
845#--------------------------------------------------------------------------- 186#---------------------------------------------------------------------------
846
847# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
848# generate Latex output.
849
850GENERATE_LATEX = NO 187GENERATE_LATEX = NO
851
852# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
853# If a relative path is entered the value of OUTPUT_DIRECTORY will be
854# put in front of it. If left blank `latex' will be used as the default path.
855
856LATEX_OUTPUT = latex 188LATEX_OUTPUT = latex
857
858# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
859# invoked. If left blank `latex' will be used as the default command name.
860
861LATEX_CMD_NAME = latex 189LATEX_CMD_NAME = latex
862
863# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
864# generate index for LaTeX. If left blank `makeindex' will be used as the
865# default command name.
866
867MAKEINDEX_CMD_NAME = makeindex 190MAKEINDEX_CMD_NAME = makeindex
868
869# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
870# LaTeX documents. This may be useful for small projects and may help to
871# save some trees in general.
872
873COMPACT_LATEX = NO 191COMPACT_LATEX = NO
874
875# The PAPER_TYPE tag can be used to set the paper type that is used
876# by the printer. Possible values are: a4, a4wide, letter, legal and
877# executive. If left blank a4wide will be used.
878
879PAPER_TYPE = a4wide 192PAPER_TYPE = a4wide
880 193EXTRA_PACKAGES =
881# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 194LATEX_HEADER =
882# packages that should be included in the LaTeX output. 195LATEX_FOOTER =
883
884EXTRA_PACKAGES =
885
886# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
887# the generated latex document. The header should contain everything until
888# the first chapter. If it is left blank doxygen will generate a
889# standard header. Notice: only use this tag if you know what you are doing!
890
891LATEX_HEADER =
892
893# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
894# is prepared for conversion to pdf (using ps2pdf). The pdf file will
895# contain links (just like the HTML output) instead of page references
896# This makes the output suitable for online browsing using a pdf viewer.
897
898PDF_HYPERLINKS = YES 196PDF_HYPERLINKS = YES
899
900# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
901# plain latex in the generated Makefile. Set this option to YES to get a
902# higher quality PDF documentation.
903
904USE_PDFLATEX = YES 197USE_PDFLATEX = YES
905
906# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
907# command to the generated LaTeX files. This will instruct LaTeX to keep
908# running if errors occur, instead of asking the user for help.
909# This option is also used when generating formulas in HTML.
910
911LATEX_BATCHMODE = NO 198LATEX_BATCHMODE = NO
912
913# If LATEX_HIDE_INDICES is set to YES then doxygen will not
914# include the index chapters (such as File Index, Compound Index, etc.)
915# in the output.
916
917LATEX_HIDE_INDICES = NO 199LATEX_HIDE_INDICES = NO
918 200LATEX_SOURCE_CODE = NO
201LATEX_BIB_STYLE = plain
919#--------------------------------------------------------------------------- 202#---------------------------------------------------------------------------
920# configuration options related to the RTF output 203# configuration options related to the RTF output
921#--------------------------------------------------------------------------- 204#---------------------------------------------------------------------------
922
923# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
924# The RTF output is optimized for Word 97 and may not look very pretty with
925# other RTF readers or editors.
926
927GENERATE_RTF = NO 205GENERATE_RTF = NO
928
929# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
930# If a relative path is entered the value of OUTPUT_DIRECTORY will be
931# put in front of it. If left blank `rtf' will be used as the default path.
932
933RTF_OUTPUT = rtf 206RTF_OUTPUT = rtf
934
935# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
936# RTF documents. This may be useful for small projects and may help to
937# save some trees in general.
938
939COMPACT_RTF = NO 207COMPACT_RTF = NO
940
941# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
942# will contain hyperlink fields. The RTF file will
943# contain links (just like the HTML output) instead of page references.
944# This makes the output suitable for online browsing using WORD or other
945# programs which support those fields.
946# Note: wordpad (write) and others do not support links.
947
948RTF_HYPERLINKS = NO 208RTF_HYPERLINKS = NO
949 209RTF_STYLESHEET_FILE =
950# Load stylesheet definitions from file. Syntax is similar to doxygen's 210RTF_EXTENSIONS_FILE =
951# config file, i.e. a series of assignments. You only have to provide
952# replacements, missing definitions are set to their default value.
953
954RTF_STYLESHEET_FILE =
955
956# Set optional variables used in the generation of an rtf document.
957# Syntax is similar to doxygen's config file.
958
959RTF_EXTENSIONS_FILE =
960
961#--------------------------------------------------------------------------- 211#---------------------------------------------------------------------------
962# configuration options related to the man page output 212# configuration options related to the man page output
963#--------------------------------------------------------------------------- 213#---------------------------------------------------------------------------
964
965# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
966# generate man pages
967
968GENERATE_MAN = NO 214GENERATE_MAN = NO
969
970# The MAN_OUTPUT tag is used to specify where the man pages will be put.
971# If a relative path is entered the value of OUTPUT_DIRECTORY will be
972# put in front of it. If left blank `man' will be used as the default path.
973
974MAN_OUTPUT = man 215MAN_OUTPUT = man
975
976# The MAN_EXTENSION tag determines the extension that is added to
977# the generated man pages (default is the subroutine's section .3)
978
979MAN_EXTENSION = .3 216MAN_EXTENSION = .3
980
981# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
982# then it will generate one additional man file for each entity
983# documented in the real man page(s). These additional files
984# only source the real man page, but without them the man command
985# would be unable to find the correct page. The default is NO.
986
987MAN_LINKS = NO 217MAN_LINKS = NO
988
989#--------------------------------------------------------------------------- 218#---------------------------------------------------------------------------
990# configuration options related to the XML output 219# configuration options related to the XML output
991#--------------------------------------------------------------------------- 220#---------------------------------------------------------------------------
992
993# If the GENERATE_XML tag is set to YES Doxygen will
994# generate an XML file that captures the structure of
995# the code including all documentation.
996
997GENERATE_XML = NO 221GENERATE_XML = NO
998
999# The XML_OUTPUT tag is used to specify where the XML pages will be put.
1000# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1001# put in front of it. If left blank `xml' will be used as the default path.
1002
1003XML_OUTPUT = xml 222XML_OUTPUT = xml
1004 223XML_SCHEMA =
1005# The XML_SCHEMA tag can be used to specify an XML schema, 224XML_DTD =
1006# which can be used by a validating XML parser to check the
1007# syntax of the XML files.
1008
1009XML_SCHEMA =
1010
1011# The XML_DTD tag can be used to specify an XML DTD,
1012# which can be used by a validating XML parser to check the
1013# syntax of the XML files.
1014
1015XML_DTD =
1016
1017# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
1018# dump the program listings (including syntax highlighting
1019# and cross-referencing information) to the XML output. Note that
1020# enabling this will significantly increase the size of the XML output.
1021
1022XML_PROGRAMLISTING = YES 225XML_PROGRAMLISTING = YES
1023
1024#--------------------------------------------------------------------------- 226#---------------------------------------------------------------------------
1025# configuration options for the AutoGen Definitions output 227# configuration options for the AutoGen Definitions output
1026#--------------------------------------------------------------------------- 228#---------------------------------------------------------------------------
1027
1028# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
1029# generate an AutoGen Definitions (see autogen.sf.net) file
1030# that captures the structure of the code including all
1031# documentation. Note that this feature is still experimental
1032# and incomplete at the moment.
1033
1034GENERATE_AUTOGEN_DEF = NO 229GENERATE_AUTOGEN_DEF = NO
1035
1036#--------------------------------------------------------------------------- 230#---------------------------------------------------------------------------
1037# configuration options related to the Perl module output 231# configuration options related to the Perl module output
1038#--------------------------------------------------------------------------- 232#---------------------------------------------------------------------------
1039
1040# If the GENERATE_PERLMOD tag is set to YES Doxygen will
1041# generate a Perl module file that captures the structure of
1042# the code including all documentation. Note that this
1043# feature is still experimental and incomplete at the
1044# moment.
1045
1046GENERATE_PERLMOD = NO 233GENERATE_PERLMOD = NO
1047
1048# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
1049# the necessary Makefile rules, Perl scripts and LaTeX code to be able
1050# to generate PDF and DVI output from the Perl module output.
1051
1052PERLMOD_LATEX = NO 234PERLMOD_LATEX = NO
1053
1054# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
1055# nicely formatted so it can be parsed by a human reader. This is useful
1056# if you want to understand what is going on. On the other hand, if this
1057# tag is set to NO the size of the Perl module output will be much smaller
1058# and Perl will parse it just the same.
1059
1060PERLMOD_PRETTY = YES 235PERLMOD_PRETTY = YES
1061 236PERLMOD_MAKEVAR_PREFIX =
1062# The names of the make variables in the generated doxyrules.make file
1063# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
1064# This is useful so different doxyrules.make files included by the same
1065# Makefile don't overwrite each other's variables.
1066
1067PERLMOD_MAKEVAR_PREFIX =
1068
1069#--------------------------------------------------------------------------- 237#---------------------------------------------------------------------------
1070# Configuration options related to the preprocessor 238# Configuration options related to the preprocessor
1071#--------------------------------------------------------------------------- 239#---------------------------------------------------------------------------
1072
1073# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
1074# evaluate all C-preprocessor directives found in the sources and include
1075# files.
1076
1077ENABLE_PREPROCESSING = YES 240ENABLE_PREPROCESSING = YES
1078
1079# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
1080# names in the source code. If set to NO (the default) only conditional
1081# compilation will be performed. Macro expansion can be done in a controlled
1082# way by setting EXPAND_ONLY_PREDEF to YES.
1083
1084MACRO_EXPANSION = NO 241MACRO_EXPANSION = NO
1085
1086# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
1087# then the macro expansion is limited to the macros specified with the
1088# PREDEFINED and EXPAND_AS_DEFINED tags.
1089
1090EXPAND_ONLY_PREDEF = NO 242EXPAND_ONLY_PREDEF = NO
1091
1092# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
1093# in the INCLUDE_PATH (see below) will be search if a #include is found.
1094
1095SEARCH_INCLUDES = YES 243SEARCH_INCLUDES = YES
1096 244INCLUDE_PATH =
1097# The INCLUDE_PATH tag can be used to specify one or more directories that 245INCLUDE_FILE_PATTERNS =
1098# contain include files that are not input files but should be processed by 246PREDEFINED =
1099# the preprocessor. 247EXPAND_AS_DEFINED =
1100
1101INCLUDE_PATH =
1102
1103# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1104# patterns (like *.h and *.hpp) to filter out the header-files in the
1105# directories. If left blank, the patterns specified with FILE_PATTERNS will
1106# be used.
1107
1108INCLUDE_FILE_PATTERNS =
1109
1110# The PREDEFINED tag can be used to specify one or more macro names that
1111# are defined before the preprocessor is started (similar to the -D option of
1112# gcc). The argument of the tag is a list of macros of the form: name
1113# or name=definition (no spaces). If the definition and the = are
1114# omitted =1 is assumed. To prevent a macro definition from being
1115# undefined via #undef or recursively expanded use the := operator
1116# instead of the = operator.
1117
1118PREDEFINED =
1119
1120# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1121# this tag can be used to specify a list of macro names that should be expanded.
1122# The macro definition that is found in the sources will be used.
1123# Use the PREDEFINED tag if you want to use a different macro definition.
1124
1125EXPAND_AS_DEFINED =
1126
1127# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
1128# doxygen's preprocessor will remove all function-like macros that are alone
1129# on a line, have an all uppercase name, and do not end with a semicolon. Such
1130# function macros are typically used for boiler-plate code, and will confuse
1131# the parser if not removed.
1132
1133SKIP_FUNCTION_MACROS = YES 248SKIP_FUNCTION_MACROS = YES
1134
1135#--------------------------------------------------------------------------- 249#---------------------------------------------------------------------------
1136# Configuration::additions related to external references 250# Configuration::additions related to external references
1137#--------------------------------------------------------------------------- 251#---------------------------------------------------------------------------
1138 252TAGFILES =
1139# The TAGFILES option can be used to specify one or more tagfiles. 253GENERATE_TAGFILE =
1140# Optionally an initial location of the external documentation
1141# can be added for each tagfile. The format of a tag file without
1142# this location is as follows:
1143# TAGFILES = file1 file2 ...
1144# Adding location for the tag files is done as follows:
1145# TAGFILES = file1=loc1 "file2 = loc2" ...
1146# where "loc1" and "loc2" can be relative or absolute paths or
1147# URLs. If a location is present for each tag, the installdox tool
1148# does not have to be run to correct the links.
1149# Note that each tag file must have a unique name
1150# (where the name does NOT include the path)
1151# If a tag file is not located in the directory in which doxygen
1152# is run, you must also specify the path to the tagfile here.
1153
1154TAGFILES =
1155
1156# When a file name is specified after GENERATE_TAGFILE, doxygen will create
1157# a tag file that is based on the input files it reads.
1158
1159GENERATE_TAGFILE =
1160
1161# If the ALLEXTERNALS tag is set to YES all external classes will be listed
1162# in the class index. If set to NO only the inherited external classes
1163# will be listed.
1164
1165ALLEXTERNALS = NO 254ALLEXTERNALS = NO
1166
1167# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
1168# in the modules index. If set to NO, only the current project's groups will
1169# be listed.
1170
1171EXTERNAL_GROUPS = YES 255EXTERNAL_GROUPS = YES
1172
1173# The PERL_PATH should be the absolute path and name of the perl script
1174# interpreter (i.e. the result of `which perl').
1175
1176PERL_PATH = /usr/bin/perl 256PERL_PATH = /usr/bin/perl
1177
1178#--------------------------------------------------------------------------- 257#---------------------------------------------------------------------------
1179# Configuration options related to the dot tool 258# Configuration options related to the dot tool
1180#--------------------------------------------------------------------------- 259#---------------------------------------------------------------------------
1181
1182# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
1183# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
1184# or super classes. Setting the tag to NO turns the diagrams off. Note that
1185# this option is superseded by the HAVE_DOT option below. This is only a
1186# fallback. It is recommended to install and use dot, since it yields more
1187# powerful graphs.
1188
1189CLASS_DIAGRAMS = YES 260CLASS_DIAGRAMS = YES
1190 261MSCGEN_PATH =
1191# You can define message sequence charts within doxygen comments using the \msc
1192# command. Doxygen will then run the mscgen tool (see
1193# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
1194# documentation. The MSCGEN_PATH tag allows you to specify the directory where
1195# the mscgen tool resides. If left empty the tool is assumed to be found in the
1196# default search path.
1197
1198MSCGEN_PATH =
1199
1200# If set to YES, the inheritance and collaboration graphs will hide
1201# inheritance and usage relations if the target is undocumented
1202# or is not a class.
1203
1204HIDE_UNDOC_RELATIONS = YES 262HIDE_UNDOC_RELATIONS = YES
1205
1206# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
1207# available from the path. This tool is part of Graphviz, a graph visualization
1208# toolkit from AT&T and Lucent Bell Labs. The other options in this section
1209# have no effect if this option is set to NO (the default)
1210
1211HAVE_DOT = NO 263HAVE_DOT = NO
1212 264DOT_NUM_THREADS = 0
1213# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 265DOT_FONTNAME = Helvetica
1214# will generate a graph for each documented class showing the direct and 266DOT_FONTSIZE = 10
1215# indirect inheritance relations. Setting this tag to YES will force the 267DOT_FONTPATH =
1216# the CLASS_DIAGRAMS tag to NO.
1217
1218CLASS_GRAPH = YES 268CLASS_GRAPH = YES
1219
1220# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
1221# will generate a graph for each documented class showing the direct and
1222# indirect implementation dependencies (inheritance, containment, and
1223# class references variables) of the class with other documented classes.
1224
1225COLLABORATION_GRAPH = YES 269COLLABORATION_GRAPH = YES
1226
1227# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
1228# will generate a graph for groups, showing the direct groups dependencies
1229
1230GROUP_GRAPHS = YES 270GROUP_GRAPHS = YES
1231
1232# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
1233# collaboration diagrams in a style similar to the OMG's Unified Modeling
1234# Language.
1235
1236UML_LOOK = NO 271UML_LOOK = NO
1237 272UML_LIMIT_NUM_FIELDS = 10
1238# If set to YES, the inheritance and collaboration graphs will show the
1239# relations between templates and their instances.
1240
1241TEMPLATE_RELATIONS = NO 273TEMPLATE_RELATIONS = NO
1242
1243# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
1244# tags are set to YES then doxygen will generate a graph for each documented
1245# file showing the direct and indirect include dependencies of the file with
1246# other documented files.
1247
1248INCLUDE_GRAPH = YES 274INCLUDE_GRAPH = YES
1249
1250# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
1251# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
1252# documented header file showing the documented files that directly or
1253# indirectly include this file.
1254
1255INCLUDED_BY_GRAPH = YES 275INCLUDED_BY_GRAPH = YES
1256
1257# If the CALL_GRAPH and HAVE_DOT options are set to YES then
1258# doxygen will generate a call dependency graph for every global function
1259# or class method. Note that enabling this option will significantly increase
1260# the time of a run. So in most cases it will be better to enable call graphs
1261# for selected functions only using the \callgraph command.
1262
1263CALL_GRAPH = NO 276CALL_GRAPH = NO
1264
1265# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
1266# doxygen will generate a caller dependency graph for every global function
1267# or class method. Note that enabling this option will significantly increase
1268# the time of a run. So in most cases it will be better to enable caller
1269# graphs for selected functions only using the \callergraph command.
1270
1271CALLER_GRAPH = NO 277CALLER_GRAPH = NO
1272
1273# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
1274# will graphical hierarchy of all classes instead of a textual one.
1275
1276GRAPHICAL_HIERARCHY = YES 278GRAPHICAL_HIERARCHY = YES
1277
1278# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
1279# then doxygen will show the dependencies a directory has on other directories
1280# in a graphical way. The dependency relations are determined by the #include
1281# relations between the files in the directories.
1282
1283DIRECTORY_GRAPH = YES 279DIRECTORY_GRAPH = YES
1284
1285# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
1286# generated by dot. Possible values are png, jpg, or gif
1287# If left blank png will be used.
1288
1289DOT_IMAGE_FORMAT = png 280DOT_IMAGE_FORMAT = png
1290 281INTERACTIVE_SVG = NO
1291# The tag DOT_PATH can be used to specify the path where the dot tool can be 282DOT_PATH =
1292# found. If left blank, it is assumed the dot tool can be found in the path. 283DOTFILE_DIRS =
1293 284MSCFILE_DIRS =
1294DOT_PATH =
1295
1296# The DOTFILE_DIRS tag can be used to specify one or more directories that
1297# contain dot files that are included in the documentation (see the
1298# \dotfile command).
1299
1300DOTFILE_DIRS =
1301
1302# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
1303# nodes that will be shown in the graph. If the number of nodes in a graph
1304# becomes larger than this value, doxygen will truncate the graph, which is
1305# visualized by representing a node as a red box. Note that doxygen if the
1306# number of direct children of the root node in a graph is already larger than
1307# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
1308# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
1309
1310DOT_GRAPH_MAX_NODES = 50 285DOT_GRAPH_MAX_NODES = 50
1311
1312# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
1313# graphs generated by dot. A depth value of 3 means that only nodes reachable
1314# from the root by following a path via at most 3 edges will be shown. Nodes
1315# that lay further from the root node will be omitted. Note that setting this
1316# option to 1 or 2 may greatly reduce the computation time needed for large
1317# code bases. Also note that the size of a graph can be further restricted by
1318# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
1319
1320MAX_DOT_GRAPH_DEPTH = 0 286MAX_DOT_GRAPH_DEPTH = 0
1321
1322# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
1323# background. This is enabled by default, which results in a transparent
1324# background. Warning: Depending on the platform used, enabling this option
1325# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
1326# become hard to read).
1327
1328DOT_TRANSPARENT = YES 287DOT_TRANSPARENT = YES
1329
1330# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
1331# files in one run (i.e. multiple -o and -T options on the command line). This
1332# makes dot run faster, but since only newer versions of dot (>1.8.10)
1333# support this, this feature is disabled by default.
1334
1335DOT_MULTI_TARGETS = NO 288DOT_MULTI_TARGETS = NO
1336
1337# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
1338# generate a legend page explaining the meaning of the various boxes and
1339# arrows in the dot generated graphs.
1340
1341GENERATE_LEGEND = YES 289GENERATE_LEGEND = YES
1342
1343# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
1344# remove the intermediate dot files that are used to generate
1345# the various graphs.
1346
1347DOT_CLEANUP = YES 290DOT_CLEANUP = YES
1348
1349#---------------------------------------------------------------------------
1350# Configuration::additions related to the search engine
1351#---------------------------------------------------------------------------
1352
1353# The SEARCHENGINE tag specifies whether or not a search engine should be
1354# used. If set to NO the values of all tags below this one will be ignored.
1355
1356SEARCHENGINE = YES
diff --git a/prebuild.xml b/prebuild.xml
index 7fff2e0..f1964f3 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/"/>
@@ -1861,6 +1870,41 @@
1861 <Reference name="OpenSim.Framework.Console"/> 1870 <Reference name="OpenSim.Framework.Console"/>
1862 <Reference name="OpenSim.Region.Physics.Manager"/> 1871 <Reference name="OpenSim.Region.Physics.Manager"/>
1863 <Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/> 1872 <Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/>
1873 <Reference name="BulletXNA.dll" path="../../../../bin/"/>
1874 <Reference name="log4net.dll" path="../../../../bin/"/>
1875
1876 <Files>
1877 <Match pattern="*.cs" recurse="true">
1878 <Exclude name="Tests" pattern="Tests"/>
1879 </Match>
1880 </Files>
1881 </Project>
1882
1883 <Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.BulletSNPlugin" path="OpenSim/Region/Physics/BulletSNPlugin" type="Library">
1884 <Configuration name="Debug">
1885 <Options>
1886 <OutputPath>../../../../bin/Physics/</OutputPath>
1887 </Options>
1888 </Configuration>
1889 <Configuration name="Release">
1890 <Options>
1891 <OutputPath>../../../../bin/Physics/</OutputPath>
1892 </Options>
1893 </Configuration>
1894
1895 <ReferencePath>../../../../bin/</ReferencePath>
1896 <Reference name="System"/>
1897 <Reference name="System.Core"/>
1898 <Reference name="System.Xml"/>
1899 <Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
1900 <Reference name="Nini.dll" path="../../../../bin/"/>
1901 <Reference name="OpenSim.Framework"/>
1902 <Reference name="OpenSim.Region.Framework"/>
1903 <Reference name="OpenSim.Region.CoreModules"/>
1904 <Reference name="OpenSim.Framework.Console"/>
1905 <Reference name="OpenSim.Region.Physics.Manager"/>
1906 <Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/>
1907 <Reference name="BulletXNA.dll" path="../../../../bin/"/>
1864 <Reference name="log4net.dll" path="../../../../bin/"/> 1908 <Reference name="log4net.dll" path="../../../../bin/"/>
1865 1909
1866 <Files> 1910 <Files>
@@ -2167,7 +2211,7 @@
2167 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 2211 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
2168 <Reference name="OpenMetaverse" path="../../../bin/"/> 2212 <Reference name="OpenMetaverse" path="../../../bin/"/>
2169 <Reference name="Nini" path="../../../bin/"/> 2213 <Reference name="Nini" path="../../../bin/"/>
2170 <Reference name="Mono.Addins"/> 2214 <Reference name="Mono.Addins" path="../../../bin/"/>
2171 <Reference name="log4net" path="../../../bin/"/> 2215 <Reference name="log4net" path="../../../bin/"/>
2172 <Files> 2216 <Files>
2173 <Match pattern="*.cs" recurse="true"/> 2217 <Match pattern="*.cs" recurse="true"/>
@@ -2497,7 +2541,9 @@
2497 <Reference name="log4net" path="../../../../../bin/"/> 2541 <Reference name="log4net" path="../../../../../bin/"/>
2498 2542
2499 <Files> 2543 <Files>
2500 <Match pattern="*.cs" recurse="true"/> 2544 <Match pattern="*.cs" recurse="true">
2545 <Exclude name="Tests" pattern="Tests"/>
2546 </Match>
2501 </Files> 2547 </Files>
2502 </Project> 2548 </Project>
2503 2549
@@ -2576,7 +2622,7 @@
2576 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 2622 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
2577 <Reference name="OpenSim.Region.Physics.Manager"/> 2623 <Reference name="OpenSim.Region.Physics.Manager"/>
2578 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/> 2624 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
2579 <Reference name="Mono.Addins"/> 2625 <Reference name="Mono.Addins" path="../../../bin/"/>
2580 2626
2581 <!-- For scripting in funny languages by default --> 2627 <!-- For scripting in funny languages by default -->
2582 <Reference name="XMLRPC" path="../../../bin/"/> 2628 <Reference name="XMLRPC" path="../../../bin/"/>
@@ -2807,12 +2853,13 @@
2807 <Reference name="nunit.framework" path="../../../bin/"/> 2853 <Reference name="nunit.framework" path="../../../bin/"/>
2808 <Reference name="OpenMetaverse" path="../../../bin/"/> 2854 <Reference name="OpenMetaverse" path="../../../bin/"/>
2809 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 2855 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
2856 <Reference name="OpenSim.Data"/>
2857 <Reference name="OpenSim.Data.Null"/>
2810 <Reference name="OpenSim.Framework"/> 2858 <Reference name="OpenSim.Framework"/>
2811 <Reference name="OpenSim.Framework.Communications"/> 2859 <Reference name="OpenSim.Framework.Communications"/>
2812 <Reference name="OpenSim.Framework.Console"/> 2860 <Reference name="OpenSim.Framework.Console"/>
2813 <Reference name="OpenSim.Framework.Servers"/> 2861 <Reference name="OpenSim.Framework.Servers"/>
2814 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 2862 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
2815 <Reference name="OpenSim.Data"/>
2816 <Reference name="OpenSim.Services.Interfaces"/> 2863 <Reference name="OpenSim.Services.Interfaces"/>
2817 <Reference name="OpenSim.Server.Base"/> 2864 <Reference name="OpenSim.Server.Base"/>
2818 <Reference name="OpenSim.Region.Framework"/> 2865 <Reference name="OpenSim.Region.Framework"/>
@@ -2838,10 +2885,11 @@
2838 </Configuration> 2885 </Configuration>
2839 2886
2840 <ReferencePath>../../bin/</ReferencePath> 2887 <ReferencePath>../../bin/</ReferencePath>
2841 <Reference name="OpenSim.Framework"/>
2842 <Reference name="Nini" path="../../bin/"/> 2888 <Reference name="Nini" path="../../bin/"/>
2843 <Reference name="nunit.framework" path="../../bin/"/> 2889 <Reference name="nunit.framework" path="../../bin/"/>
2844 <Reference name="OpenSim"/> 2890 <Reference name="OpenSim"/>
2891 <Reference name="OpenSim.Framework"/>
2892 <Reference name="OpenSim.Tests.Common"/>
2845 <Files> 2893 <Files>
2846 <Match pattern="*.cs" recurse="false"/> 2894 <Match pattern="*.cs" recurse="false"/>
2847 </Files> 2895 </Files>
@@ -3104,6 +3152,7 @@
3104 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 3152 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
3105 <Reference name="OpenSim.Region.Framework"/> 3153 <Reference name="OpenSim.Region.Framework"/>
3106 <Reference name="OpenSim.Region.CoreModules"/> 3154 <Reference name="OpenSim.Region.CoreModules"/>
3155 <Reference name="OpenSim.Region.OptionalModules"/>
3107 <Reference name="OpenSim.Region.Physics.Manager"/> 3156 <Reference name="OpenSim.Region.Physics.Manager"/>
3108 <Reference name="OpenSim.Region.ScriptEngine.Shared"/> 3157 <Reference name="OpenSim.Region.ScriptEngine.Shared"/>
3109 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/> 3158 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/>
@@ -3362,6 +3411,7 @@
3362 <Reference name="OpenSim.Region.ScriptEngine.Shared"/> 3411 <Reference name="OpenSim.Region.ScriptEngine.Shared"/>
3363 <Reference name="OpenSim.Region.ScriptEngine.Shared.Api"/> 3412 <Reference name="OpenSim.Region.ScriptEngine.Shared.Api"/>
3364 <Reference name="OpenSim.Region.ScriptEngine.Shared.Api.Runtime"/> 3413 <Reference name="OpenSim.Region.ScriptEngine.Shared.Api.Runtime"/>
3414 <Reference name="OpenSim.Region.ScriptEngine.Shared.Instance"/>
3365 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/> 3415 <Reference name="OpenSim.Region.ScriptEngine.XEngine"/>
3366 <Reference name="OpenSim.Services.Interfaces"/> 3416 <Reference name="OpenSim.Services.Interfaces"/>
3367 <Reference name="OpenSim.Tests.Common"/> 3417 <Reference name="OpenSim.Tests.Common"/>
@@ -3385,6 +3435,7 @@
3385 <!-- SADLY the way this works means you need to keep adding these paths --> 3435 <!-- SADLY the way this works means you need to keep adding these paths -->
3386 <Match path="Shared/Tests" pattern="*.cs" recurse="true"/> 3436 <Match path="Shared/Tests" pattern="*.cs" recurse="true"/>
3387 <Match path="Shared/CodeTools/Tests" pattern="*.cs" recurse="true"/> 3437 <Match path="Shared/CodeTools/Tests" pattern="*.cs" recurse="true"/>
3438 <Match path="Shared/Instance/Tests" pattern="*.cs" recurse="true"/>
3388 <Match path="XEngine/Tests" pattern="*.cs" recurse="true"/> 3439 <Match path="XEngine/Tests" pattern="*.cs" recurse="true"/>
3389 </Files> 3440 </Files>
3390 </Project> 3441 </Project>
@@ -3414,6 +3465,7 @@
3414 <Reference name="OpenSim.Framework.Console"/> 3465 <Reference name="OpenSim.Framework.Console"/>
3415 <Reference name="OpenSim.Region.Physics.Manager"/> 3466 <Reference name="OpenSim.Region.Physics.Manager"/>
3416 <Reference name="OpenSim.Region.Physics.OdePlugin" path="../../../../../bin/Physics/"/> 3467 <Reference name="OpenSim.Region.Physics.OdePlugin" path="../../../../../bin/Physics/"/>
3468 <Reference name="OpenSim.Tests.Common"/>
3417 <Reference name="Ode.NET" path="../../../../../bin/"/> 3469 <Reference name="Ode.NET" path="../../../../../bin/"/>
3418 <Reference name="nunit.framework" path="../../../../../bin/"/> 3470 <Reference name="nunit.framework" path="../../../../../bin/"/>
3419 <Reference name="log4net" path="../../../../../bin/"/> 3471 <Reference name="log4net" path="../../../../../bin/"/>
diff --git a/share/Schemas/SceneObjectPart0.xsd b/share/Schemas/SceneObjectPart0.xsd
deleted file mode 100644
index 0da7618..0000000
--- a/share/Schemas/SceneObjectPart0.xsd
+++ /dev/null
@@ -1,166 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
3 <xs:import namespace="http://microsoft.com/wsdl/types/" />
4 <xs:import namespace="http://www.w3.org/2001/XMLSchema" />
5 <xs:element name="SceneObjectPart" nillable="true" type="SceneObjectPart" />
6 <xs:complexType name="SceneObjectPart">
7 <xs:sequence>
8 <xs:element minOccurs="1" maxOccurs="1" name="LastOwnerID" type="LLUUID" />
9 <xs:element minOccurs="1" maxOccurs="1" name="OwnerID" type="LLUUID" />
10 <xs:element minOccurs="1" maxOccurs="1" name="GroupID" type="LLUUID" />
11 <xs:element minOccurs="1" maxOccurs="1" name="OwnershipCost" type="xs:int" />
12 <xs:element minOccurs="1" maxOccurs="1" name="ObjectSaleType" type="xs:unsignedByte" />
13 <xs:element minOccurs="1" maxOccurs="1" name="SalePrice" type="xs:int" />
14 <xs:element minOccurs="1" maxOccurs="1" name="Category" type="xs:unsignedInt" />
15 <xs:element minOccurs="1" maxOccurs="1" name="CreationDate" type="xs:int" />
16 <xs:element minOccurs="1" maxOccurs="1" name="ParentID" type="xs:unsignedInt" />
17 <xs:element minOccurs="1" maxOccurs="1" name="m_sitTargetAvatar" type="LLUUID" />
18 <xs:element minOccurs="1" maxOccurs="1" name="BaseMask" type="xs:unsignedInt" />
19 <xs:element minOccurs="1" maxOccurs="1" name="OwnerMask" type="xs:unsignedInt" />
20 <xs:element minOccurs="1" maxOccurs="1" name="GroupMask" type="xs:unsignedInt" />
21 <xs:element minOccurs="1" maxOccurs="1" name="EveryoneMask" type="xs:unsignedInt" />
22 <xs:element minOccurs="1" maxOccurs="1" name="NextOwnerMask" type="xs:unsignedInt" />
23 <xs:element minOccurs="1" maxOccurs="1" name="Flags" type="ObjectFlags" />
24 <xs:element minOccurs="1" maxOccurs="1" name="CreatorID" type="LLUUID" />
25 <xs:element minOccurs="1" maxOccurs="1" name="FolderID" type="LLUUID" />
26 <xs:element minOccurs="1" maxOccurs="1" name="InventorySerial" type="xs:unsignedInt" />
27 <xs:element minOccurs="0" maxOccurs="1" name="TaskInventory">
28 <xs:complexType>
29 <xs:sequence>
30 <xs:element ref="xs:schema" />
31 <xs:any />
32 </xs:sequence>
33 </xs:complexType>
34 </xs:element>
35 <xs:element minOccurs="1" maxOccurs="1" name="ObjectFlags" type="xs:unsignedInt" />
36 <xs:element minOccurs="1" maxOccurs="1" name="UUID" type="LLUUID" />
37 <xs:element minOccurs="1" maxOccurs="1" name="LocalId" type="xs:unsignedInt" />
38 <xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
39 <xs:element minOccurs="1" maxOccurs="1" name="Material" type="xs:unsignedByte" />
40 <xs:element minOccurs="1" maxOccurs="1" name="RegionHandle" type="xs:unsignedLong" />
41 <xs:element minOccurs="1" maxOccurs="1" name="ScriptAccessPin" type="xs:int" />
42 <xs:element minOccurs="1" maxOccurs="1" name="GroupPosition" type="LLVector3" />
43 <xs:element minOccurs="1" maxOccurs="1" name="OffsetPosition" type="LLVector3" />
44 <xs:element minOccurs="1" maxOccurs="1" name="RotationOffset" type="LLQuaternion" />
45 <xs:element minOccurs="1" maxOccurs="1" name="Velocity" type="LLVector3" />
46 <xs:element minOccurs="1" maxOccurs="1" name="RotationalVelocity" type="LLVector3" />
47 <xs:element minOccurs="1" maxOccurs="1" name="AngularVelocity" type="LLVector3" />
48 <xs:element minOccurs="1" maxOccurs="1" name="Acceleration" type="LLVector3" />
49 <xs:element minOccurs="0" maxOccurs="1" name="Description" type="xs:string" />
50 <xs:element minOccurs="1" maxOccurs="1" name="Color" type="Color" />
51 <xs:element minOccurs="0" maxOccurs="1" name="Text" type="xs:string" />
52 <xs:element minOccurs="0" maxOccurs="1" name="SitName" type="xs:string" />
53 <xs:element minOccurs="0" maxOccurs="1" name="TouchName" type="xs:string" />
54 <xs:element minOccurs="1" maxOccurs="1" name="LinkNum" type="xs:int" />
55 <xs:element minOccurs="1" maxOccurs="1" name="ClickAction" type="xs:unsignedByte" />
56 <xs:element minOccurs="0" maxOccurs="1" name="Shape" type="PrimitiveBaseShape" />
57 <xs:element minOccurs="1" maxOccurs="1" name="Scale" type="LLVector3" />
58 <xs:element minOccurs="1" maxOccurs="1" name="UpdateFlag" type="xs:unsignedByte" />
59 </xs:sequence>
60 </xs:complexType>
61 <xs:complexType name="LLUUID">
62 <xs:sequence>
63 <xs:element minOccurs="1" maxOccurs="1" name="UUID" xmlns:q1="http://microsoft.com/wsdl/types/" type="q1:guid" />
64 </xs:sequence>
65 </xs:complexType>
66 <xs:simpleType name="ObjectFlags">
67 <xs:list>
68 <xs:simpleType>
69 <xs:restriction base="xs:string">
70 <xs:enumeration value="None" />
71 <xs:enumeration value="Physics" />
72 <xs:enumeration value="CreateSelected" />
73 <xs:enumeration value="ObjectModify" />
74 <xs:enumeration value="ObjectCopy" />
75 <xs:enumeration value="ObjectAnyOwner" />
76 <xs:enumeration value="ObjectYouOwner" />
77 <xs:enumeration value="Scripted" />
78 <xs:enumeration value="Touch" />
79 <xs:enumeration value="ObjectMove" />
80 <xs:enumeration value="Money" />
81 <xs:enumeration value="Phantom" />
82 <xs:enumeration value="InventoryEmpty" />
83 <xs:enumeration value="JointHinge" />
84 <xs:enumeration value="JointP2P" />
85 <xs:enumeration value="JointLP2P" />
86 <xs:enumeration value="JointWheel" />
87 <xs:enumeration value="AllowInventoryDrop" />
88 <xs:enumeration value="ObjectTransfer" />
89 <xs:enumeration value="ObjectGroupOwned" />
90 <xs:enumeration value="ObjectYouOfficer" />
91 <xs:enumeration value="CameraDecoupled" />
92 <xs:enumeration value="AnimSource" />
93 <xs:enumeration value="CameraSource" />
94 <xs:enumeration value="CastShadows" />
95 <xs:enumeration value="ObjectOwnerModify" />
96 <xs:enumeration value="TemporaryOnRez" />
97 <xs:enumeration value="Temporary" />
98 <xs:enumeration value="ZlibCompressed" />
99 </xs:restriction>
100 </xs:simpleType>
101 </xs:list>
102 </xs:simpleType>
103 <xs:complexType name="LLVector3">
104 <xs:sequence>
105 <xs:element minOccurs="1" maxOccurs="1" name="X" type="xs:float" />
106 <xs:element minOccurs="1" maxOccurs="1" name="Y" type="xs:float" />
107 <xs:element minOccurs="1" maxOccurs="1" name="Z" type="xs:float" />
108 </xs:sequence>
109 </xs:complexType>
110 <xs:complexType name="LLQuaternion">
111 <xs:sequence>
112 <xs:element minOccurs="1" maxOccurs="1" name="X" type="xs:float" />
113 <xs:element minOccurs="1" maxOccurs="1" name="Y" type="xs:float" />
114 <xs:element minOccurs="1" maxOccurs="1" name="Z" type="xs:float" />
115 <xs:element minOccurs="1" maxOccurs="1" name="W" type="xs:float" />
116 </xs:sequence>
117 </xs:complexType>
118 <xs:complexType name="Color" />
119 <xs:complexType name="PrimitiveBaseShape">
120 <xs:sequence>
121 <xs:element minOccurs="1" maxOccurs="1" name="PathBegin" type="xs:unsignedShort" />
122 <xs:element minOccurs="1" maxOccurs="1" name="PathCurve" type="xs:unsignedByte" />
123 <xs:element minOccurs="1" maxOccurs="1" name="PathEnd" type="xs:unsignedShort" />
124 <xs:element minOccurs="1" maxOccurs="1" name="PathRadiusOffset" type="xs:byte" />
125 <xs:element minOccurs="1" maxOccurs="1" name="PathRevolutions" type="xs:unsignedByte" />
126 <xs:element minOccurs="1" maxOccurs="1" name="PathScaleX" type="xs:unsignedByte" />
127 <xs:element minOccurs="1" maxOccurs="1" name="PathScaleY" type="xs:unsignedByte" />
128 <xs:element minOccurs="1" maxOccurs="1" name="PathShearX" type="xs:unsignedByte" />
129 <xs:element minOccurs="1" maxOccurs="1" name="PathShearY" type="xs:unsignedByte" />
130 <xs:element minOccurs="1" maxOccurs="1" name="PathSkew" type="xs:byte" />
131 <xs:element minOccurs="1" maxOccurs="1" name="PathTaperX" type="xs:byte" />
132 <xs:element minOccurs="1" maxOccurs="1" name="PathTaperY" type="xs:byte" />
133 <xs:element
134 <xs:element minOccurs="1" maxOccurs="1" name="PathTwistBegin" type="xs:byte" />
135 <xs:element minOccurs="1" maxOccurs="1" name="PCode" type="xs:unsignedByte" />
136 <xs:element minOccurs="1" maxOccurs="1" name="ProfileBegin" type="xs:unsignedShort" />
137 <xs:element minOccurs="1" maxOccurs="1" name="ProfileEnd" type="xs:unsignedShort" />
138 <xs:element minOccurs="1" maxOccurs="1" name="ProfileHollow" type="xs:unsignedShort" />
139 <xs:element minOccurs="1" maxOccurs="1" name="Scale" type="LLVector3" />
140 <xs:element minOccurs="1" maxOccurs="1" name="State" type="xs:unsignedByte" />
141 <xs:element minOccurs="1" maxOccurs="1" name="ProfileShape" type="ProfileShape" />
142 <xs:element minOccurs="1" maxOccurs="1" name="HollowShape" type="HollowShape" />
143 <xs:element minOccurs="1" maxOccurs="1" name="ProfileCurve" type="xs:unsignedByte" />
144 <xs:element minOccurs="0" maxOccurs="1" name="TextureEntry" type="xs:base64Binary" />
145 <xs:element minOccurs="0" maxOccurs="1" name="ExtraParams" type="xs:base64Binary" />
146 </xs:sequence>
147 </xs:complexType>
148 <xs:simpleType name="ProfileShape">
149 <xs:restriction base="xs:string">
150 <xs:enumeration value="Circle" />
151 <xs:enumeration value="Square" />
152 <xs:enumeration value="IsometricTriangle" />
153 <xs:enumeration value="EquilateralTriangle" />
154 <xs:enumeration value="RightTriangle" />
155 <xs:enumeration value="HalfCircle" />
156 </xs:restriction>
157 </xs:simpleType>
158 <xs:simpleType name="HollowShape">
159 <xs:restriction base="xs:string">
160 <xs:enumeration value="Same" />
161 <xs:enumeration value="Circle" />
162 <xs:enumeration value="Square" />
163 <xs:enumeration value="Triangle" />
164 </xs:restriction>
165 </xs:simpleType>
166</xs:schema>
diff --git a/share/Schemas/SceneObjectPart1.xsd b/share/Schemas/SceneObjectPart1.xsd
deleted file mode 100644
index 2f38087..0000000
--- a/share/Schemas/SceneObjectPart1.xsd
+++ /dev/null
@@ -1,8 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xs:schema xmlns:tns="http://microsoft.com/wsdl/types/" elementFormDefault="qualified" targetNamespace="http://microsoft.com/wsdl/types/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
3 <xs:simpleType name="guid">
4 <xs:restriction base="xs:string">
5 <xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" />
6 </xs:restriction>
7 </xs:simpleType>
8</xs:schema>
diff --git a/share/php/generateUserFunction.php b/share/php/generateUserFunction.php
deleted file mode 100755
index a262bf5..0000000
--- a/share/php/generateUserFunction.php
+++ /dev/null
@@ -1,46 +0,0 @@
1<?php
2 // GenerateUser (v1.0)
3 // Creates a new user account, and returns it into an associative array.
4 // --
5 // $firstname - The users firstname
6 // $lastname - The users lastname
7 // $password - the users password
8 // $home - the regionhandle of the users home location
9 // --
10 function generateUser($firstname,$lastname,$password,$home) {
11 $user = array();
12 $user['UUID'] = sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
13 mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
14 mt_rand( 0, 0x0fff ) | 0x4000,
15 mt_rand( 0, 0x3fff ) | 0x8000,
16 mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) );
17 $user['username'] = $firstname;
18 $user['lastname'] = $lastname;
19
20 $user['passwordSalt'] = md5(microtime() . mt_rand(0,0xffff));
21 $user['passwordHash'] = md5(md5($password) . ":" . $user['passwordSalt']);
22
23 $user['homeRegion'] = $home;
24 $user['homeLocationX'] = 128;
25 $user['homeLocationY'] = 128;
26 $user['homeLocationZ'] = 128;
27 $user['homeLookAtX'] = 15;
28 $user['homeLookAtY'] = 15;
29 $user['homeLookAtZ'] = 15;
30
31 $user['created'] = time();
32 $user['lastLogin'] = 0;
33
34 $user['userInventoryURI'] = "http://inventory.server.tld:8004/";
35 $user['userAssetURI'] = "http://asset.server.tld:8003/";
36
37 $user['profileCanDoMask'] = 0;
38 $user['profileWantDoMask'] = 0;
39 $user['profileAboutText'] = "I am a user.";
40 $user['profileFirstText'] = "Stuff.";
41 $user['profileImage'] = sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', 0, 0, 0, 0, 0, 0, 0, 0 );
42 $user['profileFirstImage'] = sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', 0, 0, 0, 0, 0, 0, 0, 0 );
43
44 return $user;
45 }
46?> \ No newline at end of file